Там так много ответов, но люди всегда запутываются.Я знаю это, потому что я запутался некоторое время назад.Через некоторое время я понял концепции.
- Привязать объект / функцию вручную, чтобы поиграть с состоянием или подпорками внутри функции и избежать проблем, связанных с областью действия
Не совсем так.Вам не нужно связывать функции, чтобы играть с состоянием или реквизитом.Вы связываете функцию с 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 дал в комментариях, является знаменитой дискуссией по этому вопросу.Функции стрелок действительно медленнее, чем обычные?Да.А сколько?Не так много, я думаю.Кроме того, это верно для переданного кода.В будущем, когда они станут родными, они станут более быстрыми.
Как личное примечание.Я использовал функции стрелок все время, так как они мне нравятся.Но некоторое время назад в обсуждении кто-то сказал:
Когда я вижу функцию стрелки в классе, я думаю, что: «Эта функция используется / вызывается вне этого класса».Если я вижу обычный, я понимаю, что эта функция вызывается внутри класса.
Мне очень понравился этот подход, и теперь, если мне не нужно вызывать мою функцию за пределами моего класса, я используюобычный.