I wouldn't recommend either useState
or 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-lambda
tslint rule). There's two reasons for this:
- 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.memo
or 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.
To handle this, React provides the useCallback
hook, for memoizing callbacks:
const MyComponent = () => {
const handleClick = useCallback((e) => {
//...
}, [/* deps */])
return <OptimizedButtonComponent onClick={handleClick}>Click Me</button>;
};
useCallback
will only return a new function when necessary (whenever a value in the deps array changes), so OptimizedButtonComponent
won'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
)
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.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…