Почему JSX props не должен использовать функции стрелки или привязки?
я запускаю Линт с моим приложением React, и я получаю эту ошибку:
error JSX props should not use arrow functions react/jsx-no-bind
и здесь я запускаю функцию стрелки (внутри onClick
):
{this.state.photos.map(tile => (
<span key={tile.img}>
<Checkbox
defaultChecked={tile.checked}
onCheck={() => this.selectPicture(tile)}
style={{position: 'absolute', zIndex: 99, padding: 5, backgroundColor: 'rgba(255, 255, 255, 0.72)'}}
/>
<GridTile
title={tile.title}
subtitle={<span>by <b>{tile.author}</b></span>}
actionIcon={<IconButton onClick={() => this.handleDelete(tile)}><Delete color="white"/></IconButton>}
>
<img onClick={() => this.handleOpen(tile.img)} src={tile.img} style={{cursor: 'pointer'}}/>
</GridTile>
</span>
))}
это плохая практика, которую следует избегать? И как это лучше всего сделать?
3 ответов
почему вы не должны использовать встроенные функции стрелки в JSX props
использование функций стрелки или привязки в JSX-плохая практика, которая вредит производительности, потому что функция воссоздается на каждом рендеринге.
всякий раз, когда создается функция, предыдущая функция-это собранный мусор. Перезапуск многих элементов может создать jank в анимации.
использование встроенной функции стрелки вызовет
PureComponent
S, и компоненты, которые используютshallowCompare
наshouldComponentUpdate
способ все равно повторно. Поскольку функция стрелки prop воссоздается каждый раз, неглубокое сравнение идентифицирует его как изменение в prop, а компонент будет повторно преобразован.
как вы можете видеть в следующих 2 примерах-когда мы используем встроенную функцию стрелки,<Button>
компонент перенаправляется каждый раз (на консоли отображается текст "кнопка рендеринга").
Пример 1-PureComponent без встроенный обработчик
class Button extends React.PureComponent {
render() {
const { onClick } = this.props;
console.log('render button');
return (
<button onClick={ onClick }>Click</button>
);
}
}
class Parent extends React.Component {
state = {
counter: 0
}
onClick = () => this.setState((prevState) => ({
counter: prevState.counter + 1
}));
render() {
const { counter } = this.state;
return (
<div>
<Button onClick={ this.onClick } />
<div>{ counter }</div>
</div>
);
}
}
ReactDOM.render(
<Parent />,
document.getElementById('root')
);
<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>
Пример 2-PureComponent С встроенный обработчик
class Button extends React.PureComponent {
render() {
const { onClick } = this.props;
console.log('render button');
return (
<button onClick={ onClick }>Click</button>
);
}
}
class Parent extends React.Component {
state = {
counter: 0
}
render() {
const { counter } = this.state;
return (
<div>
<Button onClick={ () => this.setState((prevState) => ({
counter: prevState.counter + 1
})) } />
<div>{ counter }</div>
</div>
);
}
}
ReactDOM.render(
<Parent />,
document.getElementById('root')
);
<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>
методы привязки к this
без встроенных функций стрелки
-
привязка метода вручную в конструкторе:
class Button extends React.Component { constructor(props, context) { super(props, context); this.cb = this.cb.bind(this); } cb() { } render() { return ( <button onClick={ this.cb }>Click</button> ); } }
-
привязка a метод с использованием
Это потому, что функция стрелки, по-видимому, создаст новый экземпляр функции для каждого рендеринга, если он используется в свойстве JSX. Это может создать огромную нагрузку на сборщик мусора, а также помешать браузеру оптимизировать любые "горячие пути", поскольку функции будут выброшены вместо повторного использования.
вы можете увидеть все объяснение и некоторую дополнительную информацию на https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-bind.md
чтобы избежать создания новых функций с теми же аргументами, вы можете запомнить результат привязки функции, вот простая утилита с именем memobind
для этого: https://github.com/supnate/memobind