Реагируйте: Какая стрелка рекомендуется или нормальная функция? - PullRequest
0 голосов
/ 27 августа 2018

Я начал использовать функции со стрелками после того, как почувствовал, что ручное связывание функций / объектов и проблемы, связанные с областью видимости, являются головной болью, но очень недавно я понял, что лучше использовать обычную функцию (ES5), чем функцию стрелки (ES6).

Мое понимание этих функций

Нормальная функция в React:

  1. Привязка объекта / функции вручную, чтобы играть с состоянием или подпорками внутри функции и избежатьсвязанные с областью действия проблемы
  2. Привязка объекта / функции всегда в конструкторе, но не напрямую в рендере
  3. Если вы сделаете это в конструкторе, тогда Webpack создаст новый объект / функцию в файле bundle.js только один раз, когда ваш компонентрендеринг в первый раз
  4. Если вы делаете это непосредственно в рендере, тогда Webpack будет создавать новый объект / функцию в файле bundle.js каждый раз, когда ваш компонент рендерится и повторно рендерится
  5. Если вы нене связывайте, тогда вы не можете получить доступ к состоянию или реквизита.Вы должны назначить текущий объект локальной переменной, иначе this.state или this.props не определены

Функция стрелки в React:

  1. Нетнеобходимо связать объект / функцию в конструкторе или отобразить
  2. Вам не нужно зависеть от локальных переменных interms текущего объекта, т. е. пусть это = this;
  3. У вас не будет проблем с областью действия и объекта/ Привязка функции происходит автоматически

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

Это правда?Что рекомендуется?

В этой теме принят ответ Правильное использование функций стрелок в React говорит -> Это зависит от того, где именно вы используете функцию Arrow.Если в методе рендеринга используются функции Arrow, то они создают новый экземпляр, каждый раз, когда рендер вызывается так же, как работает bind.

Извините, если вы считаете, что это театральный вопрос, но это мое самое большое сомнение.Просьба предложить

Ответы [ 2 ]

0 голосов
/ 27 августа 2018

Там так много ответов, но люди всегда запутываются.Я знаю это, потому что я запутался некоторое время назад.Через некоторое время я понял концепции.

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

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

class App extends React.Component {
  state = {
    name: "foo",
  }
  aFunction() {
    console.log( this.state.name );
  }
  render() {
    return <div>{this.aFunction()}</div>;
  }
}

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

class App extends React.Component {
  state = {
    name: "foo",
  }
  aFunction() {
    console.log( this.state.name );
  }

  render() {
    return (
      <div>
        <button onClick={this.aFunction}>Click</button>
      </div>
    );
  }
}

Это не работает, поскольку вы теряете контекст.Теперь вам нужно как-то вернуть его контекст, верно?Хорошо, давайте посмотрим, как мы можем это сделать.Во-первых, я хочу связать его в обратном вызове кнопки.

<button onClick={this.aFunction.bind(this)}>Click</button>

Да, это работает.Но это будет воссоздано в каждом рендере.Итак:

Связывать объект / функцию всегда в конструкторе, но не напрямую в рендере.

Да.Не связывайте это, как я делал выше, делайте это в своем конструкторе.

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

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

Вы подводите итог того, что я пробовалобъяснить до сих пор.Но я полагаю, что это не тот веб-пакет, а ваше приложение.

Если вы не связываете, вы не можете получить доступ к состоянию или реквизиту.Вы должны назначить текущий объект локальной переменной, в противном случае this.state или this.props не определены

Опять же, если вы используете свою функцию внутри области видимости вашего класса, вам не нужносвязать это.Если вы используете эту функцию за пределами вашего класса, например, функцию обратного вызова кнопки, вы должны связать ее.Это не относится к state или props.Это связано с использованием this.

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

Теперь функции стрелок.

1.Не нужно связывать объект / функцию в конструкторе и не отображать

Да.

Вам не нужно зависеть от локальных переменных interms текущего объекта, т. Е. Пусть это = this;

Да.

У вас не будет проблем с областью действия, и привязка объекта / функции происходит автоматически

Да.

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

Как и все говорили, чтозависит от того, где вы их используете.

render() {
    return (
        <div>
            <button onClick={() => this.aFunction()}>Click</button>
        </div>
    );
}

Здесь он будет воссоздан при каждом рендере.Но если вам не нужно передавать какой-либо аргумент, вы можете использовать его по ссылке.

render() {
    return (
        <div>
            <button onClick={this.aFunction}>Click</button>
        </div>
    );
}

Это работает как предыдущий.Итак, если вы видите () в вашем методе рендеринга, эта функция воссоздается при каждом рендеринге.Обычный или стрелочный, не имеет значения.Если вы вызываете это как-то, то вы воссоздаете это.Это относится к связыванию в рендере, как aFunction.bind(this).Я вижу () там.

Итак, используйте функции по ссылкам, чтобы избежать этой проблемы.Теперь большой вопрос, что происходит, когда нам нужны аргументы?Если вы используете функцию стрелки для передачи аргумента, попробуйте изменить свою логику.

Но так ли это важно?Как сказал @Eric Kim, оптимизация - это проблема, если она вам действительно нужна.Это общее предложение, так как я слышал это от многих людей.Но лично я стараюсь избегать использования функций, если они будут воссозданы при каждом рендере.Но опять же, это абсолютно личное.

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

{
    items.map( item =>
        <button onClick={() => this.aFunction(item.name)}>Click</button>
    )
}

Эта функция будет воссоздана при каждом рендеринге для каждого элемента!Итак, измените свою логику, создайте отдельный компонент Item и отобразите его.Передайте item, aFunction как реквизит.Затем с помощью функции-обработчика в этом компоненте используйте вашу функцию.

const Item = ( props ) => {
    const handleClick = () => props.aFunction( props.item.name );
    return (
        <button onClick={handleClick}>Click</button>
    );
}

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

Вы можете применять эту логику большую часть времени.Может быть, будет несколько примеров, которые вы не можете, кто знает.Таким образом, решение остается за вами.

Кстати, сообщение Medium, которое @widged дал в комментариях, является знаменитой дискуссией по этому вопросу.Функции стрелок действительно медленнее, чем обычные?Да.А сколько?Не так много, я думаю.Кроме того, это верно для переданного кода.В будущем, когда они станут родными, они станут более быстрыми.

Как личное примечание.Я использовал функции стрелок все время, так как они мне нравятся.Но некоторое время назад в обсуждении кто-то сказал:

Когда я вижу функцию стрелки в классе, я думаю, что: «Эта функция используется / вызывается вне этого класса».Если я вижу обычный, я понимаю, что эта функция вызывается внутри класса.

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

0 голосов
/ 27 августа 2018

Если у вас есть следующий код React,

class A extends React.Component {
  constructor(props) {
    super(props)
    this.state = {name: props.name}
  }
  render() {
    return (
       <button onclick={(event)=>console.log(this.state.name)} />
    )
  }
}

меняется на следующий

class A extends React.Component {
  state = {name: this.props.name}
  render() {
    return (
       <button onclick={this.logName} />
    )
  }
  logName = (event) => {
    console.log(this.state.name)
  }
}

Таким образом, вы не создаете новые анонимные функции при каждом рендеринге.

Новый экземпляр функции создается каждый раз, когда у вас есть код, запускающий ()=>, это не magic.Посмотрите на следующие функции-члены

class A {
  memberFuncWithBinding = () => {}
  memberFuncWithoutBinding(){}
}

Обе эти функции-члены создаются только один раз, когда создается экземпляр класса.Опять же, никакой магии, но верхняя функция-член предпочтительнее, так как при использовании this внутри этой функции у вас будет правильный класс А. Это связывание.

РЕДАКТИРОВАТЬ: Слушайте, не пытайтесь оптимизировать свой код перед вамистолкнуться с проблемами.Создание новых функций каждый рендеринг медленнее, но только на долю миллисекунды.

...