javascript 在 React 中使用钩子创建事件处理程序的正确方法?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/55001372/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Correct way to create event handlers using hooks in React?
提问by Lucas
In a typical class-based React component, this is how I would create an event handler:
在典型的基于类的 React 组件中,这是我创建事件处理程序的方式:
class MyComponent extends Component {
handleClick = () => {
...
}
render() {
return <button onClick={this.handleClick}>Click Me</button>;
}
}
However, I find myself with two options when I use a hooks-based functional paradigm:
但是,当我使用基于钩子的函数范式时,我发现自己有两个选择:
const MyComponent = () => {
const [handleClick] = useState(() => () => {
...
});
return <button onClick={handleClick}>Click Me</button>;
};
or alternatively:
或者:
const MyComponent = () => {
const handleClick = useRef(() => {
...
});
return <button onClick={handleClick.current}>Click Me</button>;
};
Which one is objectively better, and for what reason? Is there another (better) way that I have not yet heard of nor discovered?
客观上哪个更好,原因是什么?有没有我还没有听说过或发现的另一种(更好的)方法?
Thank you for your help.
谢谢您的帮助。
Edit: I have put an example here on CodeSandboxshowing both methods. Neither seems to unnecessarily recreate the event handler on each render, as you can see from the code on there, so a possible performance issue is out of the question, I think.
编辑:我在 CodeSandbox 上放了一个例子,展示了这两种方法。正如您从那里的代码中看到的那样,两者似乎都没有不必要地在每次渲染时重新创建事件处理程序,因此我认为不可能出现性能问题。
回答by Retsam
I wouldn't recommend either useStateor useRef.
我不会推荐useState或useRef。
You don't actually need any hook here at all. In many cases, I'd recommend simply doing this:
你实际上根本不需要任何钩子。在许多情况下,我建议简单地这样做:
const MyComponent = () => {
const handleClick = (e) => {
//...
}
return <button onClick={handleClick}>Click Me</button>;
};
However, it's sometimes suggested to avoid declaring functions inside a render function (e.g. the jsx-no-lambdatslint rule). There's two reasons for this:
但是,有时建议避免在渲染函数中声明函数(例如jsx-no-lambdatslint 规则)。这有两个原因:
- As a performance optimization to avoid declaring unnecessary functions.
- To avoid unnecessary re-renders of pure components.
- 作为性能优化,以避免声明不必要的功能。
- 避免对纯组件进行不必要的重新渲染。
I wouldn't worry much about the first point: hooks are going to declare functions inside of functions, and it's not likely that that cost is going to be a major factor in your apps performance.
我不会太担心第一点:钩子将在函数内部声明函数,并且该成本不太可能成为您的应用程序性能的主要因素。
But the second point is sometimes valid: if a component is optimized (e.g. using React.memoor by being defined as a PureComponent) so that it only re-renders when provided new props, passing a new function instance may cause the component to re-render unnecessarily.
但第二点有时是有效的:如果一个组件被优化(例如使用React.memo或被定义为 a PureComponent)以便它只在提供新的 props 时重新渲染,传递一个新的函数实例可能会导致组件不必要地重新渲染。
To handle this, React provides the useCallbackhook, for memoizing callbacks:
为了解决这个问题,React 提供了useCallback钩子,用于记忆回调:
const MyComponent = () => {
const handleClick = useCallback((e) => {
//...
}, [/* deps */])
return <OptimizedButtonComponent onClick={handleClick}>Click Me</button>;
};
useCallbackwill only return a new function when necessary (whenever a value in the deps array changes), so OptimizedButtonComponentwon't re-render more than necessary. So this addresses issue #2. (Note that it doesn't address issue #1, every time we render, a new function is still created and passed to useCallback)
useCallback只会在必要时返回一个新函数(每当 deps 数组中的值发生变化时),因此OptimizedButtonComponent不会重新渲染超过必要的次数。所以这解决了问题#2。(请注意,它没有解决问题 #1,每次我们渲染时,仍然会创建一个新函数并将其传递给useCallback)
But I'd only do this where necessary. You could wrap every callback in useCallback, and it would work... but in most cases, it doesn't help anything: your original example with <button>won't benefit from a memoized callback, since <button>isn't an optimized component.
但我只会在必要时这样做。您可以将每个回调都包装在 中useCallback,它会起作用……但在大多数情况下,它没有任何帮助:您的原始示例<button>不会从记忆化回调中受益,因为<button>它不是优化的组件。
回答by Masih Jahangiri
If your event function is small or medium (90% of cases):
如果您的事件函数很小或中等(90% 的情况):
import React from 'react';
const Component = () => {
const handleEvent = (e) => { // React creates function whenever rendered
// small or medium function
}
return <div onClick={handleEvent}>button</div>;
};
If your event function is large memoize it (10% of cases):
如果您的事件函数很大,请记住它(10% 的情况):
import React, { useCallback } from 'react';
const Component = () => {
const handleEvent = useCallback((e) => {
// large function
}, [/* deps */]);
return <div onClick={handleEvent}>button</div>;
};

