Где я должен связать методы в компоненте React? - PullRequest
0 голосов
/ 05 сентября 2018

Я сейчас изучаю React и заметил, что многие люди связывают свои методы в конструкторе.

Как это:

class MyComponent extends React.Component {
  constructor() {
    super();
    this.myMethod = this.myMethod.bind(this);
  }

  render() {
    <button onClick={this.myMethod}>Click me</button>
  }

  myMethod() {
    // do something
  }
}

Но я привык писать что-то вроде этого:

render() {
    <button onClick={this.myMethod.bind(this)}>Click me</button>
}

И мне сказали, что использование второго метода - плохой опыт.

Так могли бы вы сказать мне разницу между первым и вторым методами? Есть плюсы и минусы? или проблемы с производительностью?

Ответы [ 6 ]

0 голосов
/ 06 сентября 2018

Это приводит к созданию новой связанной функции при каждом вызове render:

render() {
    <button onClick={this.myMethod.bind(this)}>Click me</button>
}

Обратите внимание, что если myMethod используется в нескольких местах, это требует нескольких вызовов bind и может привести к несвязанному обратному вызову, если один из bind отсутствует.

Хотя при создании экземпляра компонента создается связанная функция:

  constructor() {
    super();
    this.myMethod = this.myMethod.bind(this);
  }

Второй вариант рекомендуется.

Декоратор, такой как autobind, может использоваться для пропуска myMethod явного присваивания в конструкторе.

Как объяснено в этом ответе , методы-прототипы с bind имеют меньше недостатков, чем методы экземпляра стрелки, и обычно могут быть предпочтительными.

0 голосов
/ 05 сентября 2018

Вы должны связать в конструкторе просто потому, что второй способ будет создавать новую функцию при каждом рендере.

Но есть лучший способ просто избежать связывания. Используйте функцию стрелки.

class MyComponent extends React.Component {
  constructor() {
    super();
  }

  render() {
    <button onClick={this.myMethod}>Click me</button>
  }

  myMethod = ()=> {
    // do something
  }
}

Давайте посмотрим, как создатель Redux Дан Абрамов думает о функциях bind vs arrow -

Вопрос

С точки зрения производительности, есть ли разница между использованием стрелки функции и связывать вручную при использовании классов ES6? Используя стрелку функции методы не на прототипе класса, он будет на только экземпляр класса. Использование bind присоединит методы к классу прототип. Похоже, что связывание вручную будет иметь лучшую производительность, Означает ли это, что мы должны рассмотреть возможность использования связывания вместо стрелки функции для методов класса?

Любые предложения или комментарии действительно приветствуются!

Так что с точки зрения производительности, вы бы порекомендовали использовать

класс MyComponent extends React.Component {constructor (props) { супер (реквизит)}

methodA = () => {...}}

или

класс MyComponent extends React.Component {constructor (props) { супер (реквизит) this.methodA = this.methodA.bind (this)}

methodA () {...}}

Ответ

Эти два способа написания эквивалентны. (Второй составлен к первому.)

Использование bind присоединит методы к прототипу класса.

В вашем примере вы по-прежнему присоединяете функцию к экземпляру:

this.methodA = this.methodA.bind(this)

Так что, по сути, они одинаковы.

В Facebook мы используем второй способ («свойства класса»), но помните это все еще эксперимент, и не является частью ES6. Если вы хотите только придерживайтесь стабильного синтаксиса, тогда вы можете связать их вручную.

0 голосов
/ 05 сентября 2018

Первый подход является правильным с точки зрения производительности, поскольку при каждом рендеринге эта onClick опора будет указывать на один и тот же объект, что не так во втором примере.


Если вы посмотрите на приведенный ниже пример, вы увидите, когда я увеличу счетчик, MyPureCompOne не рендерится, а MyPureCompTwo делает. Поскольку каждый раз, когда компонент <App> рендерится, MyPureCompTwo реквизитам handleClick присваивается новый функциональный объект, и поэтому, будучи чистым компонентом, поверхностные сравнения реквизитов ложны, и он визуализируется. Этот рендеринг не был необходим. Но это не относится к MyPureCompOne, так как каждый раз, когда App рендерит, handleClick реквизит все еще указывает на тот же функциональный объект (this.handleClickOne), который был создан при первом монтировании App.

class MyPureCompOne extends React.PureComponent {
  render() {
    console.log("rendring component one");
    return <button onClick={this.props.handleClick}>First Button</button>
  }
}

class MyPureCompTwo extends React.PureComponent {
  render() {
    console.log("rendring component two");
    return <button onClick={this.props.handleClick}>Second Button</button>;
  }
}

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0
    };
    this.handleCountChange = this.handleCountChange.bind(this);
    this.handleClickOne = this.handleClickOne.bind(this);
  }

  handleCountChange() {
    this.setState(prevState => ({
      count: prevState.count + 1
    }));
  }

  handleClickOne(e) {
    console.log("Clicked..");
  }

  handleClickTwo() {
    console.log("Clicked..");
  }

  render() {
    const { count } = this.state;
    return (
      <div>
        <button onClick={this.handleCountChange}>Change Counter</button>
        <MyPureCompOne handleClick={this.handleClickOne} />;
        <MyPureCompTwo handleClick={this.handleClickTwo.bind(this)} />
      </div>
    );
  }
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
<script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>


<div id='root'></div>
0 голосов
/ 05 сентября 2018

Вы должны избегать функций стрелок и привязок при рендеринге. Нарушает производительность оптимизации, такие как shouldComponentUpdate и PureComponent.

Для отличного чтения и демонстрации вы можете обратиться это.

0 голосов
/ 05 сентября 2018

Я взял это из документации eslint-plugin-реаги:

Функция связывания или стрелка в опоре JSX создаст совершенно новую функцию для каждого рендера. Это отрицательно сказывается на производительности, так как приводит к тому, что сборщик мусора будет вызываться больше, чем необходимо. Это также может привести к ненужным повторным визуализациям, если совершенно новая функция передается в качестве реквизита компоненту, который использует проверку равенства ссылок на реквизит для определения необходимости обновления.

Как примечание от меня, использование this в вашем JSX также может сбивать с толку. Я рекомендую вам взглянуть на этот документ: https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-bind.md

0 голосов
/ 05 сентября 2018

Вы правы, и то, что другие говорили вам, также верно.

Рекомендуется выполнять связывание в конструкторе, потому что конструктор вызывается только один раз для каждого компонента, поэтому, если вы связываете конструктор, он создает новый объект / функцию только один раз в файле bundle.js Webpack, следовательно, не оказывает большого влияния

Вам не рекомендуется делать привязку непосредственно при рендеринге, потому что компонент рендерит по нескольким причинам, например, когда вы делаете setState, когда ваш компонент получает новые реквизиты, так что ваш компонент будет рендериться столько раз. Таким образом, поскольку вы привязываете напрямую при рендеринге всякий раз, когда ваш компонент рендерит, он будет создавать новую функцию каждый раз в Webpack bundle.js, и размер файла вашего пакета будет увеличиваться, что влияет на производительность, когда ваше приложение содержит тысячи компонентов и если вы делаете связывание непосредственно в визуализация в каждом компоненте.

Так что вам рекомендуется делать привязку только в конструкторе. Надеюсь, что проясняет

...