Я бы не рекомендовал useState
или useRef
.
Тебе здесь вообще не нужен крючок.Во многих случаях я бы рекомендовал просто сделать это:
const MyComponent = () => {
const handleClick = (e) => {
//...
}
return <button onClick={handleClick}>Click Me</button>;
};
Однако иногда рекомендуется избегать объявления функций внутри функции рендеринга (например, правило jsx-no-lambda
tslint).Для этого есть две причины:
- В качестве оптимизации производительности, чтобы избежать объявления ненужных функций.
- Чтобы избежать ненужных повторных визуализаций чистых компонентов.
Я бы не стал сильно беспокоиться о первом пункте: хуки будут объявлять функции внутри функций, и маловероятно, что эти затраты станут основным фактором производительности ваших приложений.
Но второй моментиногда допустимо: если компонент оптимизирован (например, с использованием React.memo
или определен как PureComponent
), так что он перерисовывается только при наличии новых реквизитов, передача нового экземпляра функции может вызвать повторную визуализацию компонента
. Для этого React предоставляет хук useCallback
для запоминания обратных вызовов:
const MyComponent = () => {
const handleClick = useCallback((e) => {
//...
}, [/* deps */])
return <OptimizedButtonComponent onClick={handleClick}>Click Me</button>;
};
useCallback
будет возвращать новую функцию только при необходимости.(всякий раз, когда изменяется значение в массиве deps), поэтому OptimizedButtonComponent
не будет перерисовывать больше, чем необходимо.Так что это решает проблему № 2.(Обратите внимание, что это не решает проблему # 1, каждый раз, когда мы выполняем рендеринг, новая функция все еще создается и передается в useCallback
)
Но я буду делать это только при необходимости.Вы можете обернуть каждый обратный вызов в useCallback
, и он будет работать ... но в большинстве случаев это ничего не поможет: ваш исходный пример с <button>
не извлечет выгоду из запомненного обратного вызова, так как <button>
isnоптимизированный компонент