У меня есть небольшой компонент для изменения языка моего сайта. Поскольку eslint настроен с помощью jsx-no-bind, он вызывает ошибку в приведенном ниже коде.
const ChangeLanguage = ({ toggleLanguage }) => {
const toggle = () => {
console.info('hi')
toggleLanguage()
}
return (
<IconButton
onClick = {toggle}
>
<Language /> // this is an svg-icon
</IconButton>
)
}
export default connect(null, { toggleLanguage })(ChangeLanguage)
Я погуглил использование jsx-no-bind. Кто-то сказал, что мы должны включить его, так как при каждом рендеринге javascript генерирует новую функцию, и это вызывает ненужный рендеринг (например, соглашение о коде airbnb[связь]). Но некоторые другие говорят, что улучшение производительности незначительно и снижает читабельность кода (например, [связь]). Вот два вопроса:
jsx-no-bind).jsx-no-bind (т. е. я должен удалить ее полностью/частично из конфигурации eslint или нет?).PS: В Интернете есть дополнительная документация о передаче стрелочных функций или методов привязки в качестве реквизита. Но я упомянул только два из них в постановке вопроса.



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Это происходит из-за того, что вы передали функцию в операторе return вашего компонента, и это создает новую функцию каждый раз, когда компонент перерисовывается.
чтобы избежать этого, вы можете использовать только его ссылку. так,
const ChangeLanguage = ({ toggleLanguage }) => {
return (
<IconButton
onClick = {toggleLanguage} // <----->
<Language /> // this is an svg-icon
</IconButton>
)
}
export default connect(null, { toggleLanguage })(ChangeLanguage)
ну, я лично не сталкивался с ситуацией, когда вы «должны» создать функцию в операторе возврата, вы можете определить функцию вне возврата или метода рендеринга и передать ее ссылку внутри. ИЛИ, если всякая надежда потеряна, вы можете просто отключить правило eslint для этого файла, написав комментарий вида: та же строка: // eslint-disable-line jsx-no-bind следующая строка: // eslint-disable-next-line jsx-no-bind весь код ниже: /* eslint-disable jsx-no-bind */
Я немного меняю код, не меняя исходной задачи. Предположим, мы также должны/хотим сделать что-то еще (например, вывести строку на консоль)... . Проблема все еще есть!
Я полагаю, потому что это все еще внутри рендеринга, поскольку это функциональный компонент, если вы переключите его на компонент, основанный на классе, вы можете определить функцию вне метода рендеринга, и это будет работать. Я не уверен, обходит ли useCallback() хук это правило или нет, предлагаю вам попробовать/поискать.
Спасибо за ваше предложение о крючке useCallback, я посмотрю на него. Но для первой части (поскольку лучше определить функциональный компонент, а не основанный на классе) теперь лучше определить класс, который подчиняется правилу jsx-no-bind, или функциональный компонент, который не подчиняется?!
eslint не жалуется, если мы делаем:
const ChangeLanguage = ({ toggleLanguage }) => {
function toggle () {
console.info('hi')
toggleLanguage()
}
return (
<IconButton
onClick = {toggle}
>
<Language /> // this is an svg-icon
</IconButton>
)
}
export default connect(null, { toggleLanguage })(ChangeLanguage)
Но я не уверен, в чем разница. Реакция в этом случае больше не создает функцию при каждом рендеринге или просто правило не распознает ее?
Решение задокументировано здесь: https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-bind.md#react-hooks
Functional components are often used alongside hooks, and the most trivial case would occur if your callback is completely independent from your state. In this case, the solution is as simple as moving the callback out of your component:
const onClick = () => {
console.info("Independent callback");
};
const Button = () => {
return (
<button type = "button" onClick = {onClick}>Label</button>
);
};
Otherwise, the idiomatic way to avoid redefining callbacks on every render would be to memoize them using the
useCallbackhook:
const Button = () => {
const [text, setText] = useState("Before click");
const onClick = useCallback(() => {
setText("After click");
}, [setText]); // Array of dependencies for which the memoization should update
return (
<button type = "button" onClick = {onClick}>{text}</button>
);
};
Ты прав. Проблема здесь решена, но что мы можем сделать, если мы должны передать функцию в качестве реквизита (в других ситуациях)... Как передать функцию в качестве реквизита onClick без ошибок (т.е. ненужный побочный эффект рендеринга)