[英]React hooks useCallback with parameters inside loop
I'm trying to learn about the hooks functionality, however I can't quite seem to figure out how I'm supposed to use the function useCallback
properly. 我正在尝试了解钩子功能,但我似乎无法弄清楚我应该如何正确使用函数
useCallback
。 As far as I understand from the rules about hooks I'm supposed to call them top-level and not within logic (such as loops). 据我所知,关于钩子的规则我应该称它们为顶级而不是逻辑(如循环)。 Which leads me to be quite confused how I'm supposed to implement
useCallback
on components that are rendered from a loop. 这让我很困惑,我应该如何在从循环中呈现的组件上实现
useCallback
。
Take a look at the following example snippet where I create 5 buttons with an onClick
handler that prints the number of the button to the console. 看一下下面的示例代码片段,其中我创建了5个带有
onClick
处理程序的按钮,该处理程序将按钮的编号打印到控制台。
const Example = (props) => { const onClick = (key) => { console.log("You clicked: ", key); }; return( <div> { _.times(5, (key) => { return ( <button onClick={() => onClick(key)}> {key} </button> ); }) } </div> ); }; console.log("hello there"); ReactDOM.render(<Example/>, document.getElementById('root'));
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.11/lodash.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script> <div id='root'> </div>
Right now it creates a new function instance everytime the Example renders due to my use of the arrow function within the <button onClick={() => onClick(key)}>
, which I do because I want the onClick
function to know which button called it. 由于我在
<button onClick={() => onClick(key)}>
使用了箭头函数,因此每次示例呈现时它都会创建一个新的函数实例,我这样做是因为我希望onClick
函数知道哪个按钮叫它。 I thought I could prevent this with the new react hooks functionality by using useCallback
, however if I apply it to the const onClick
then it would still create a new instance every render because of the inline arrow function needed to give the key
parameter, and I'm not allowed to apply it to the render within a loop as far as I know (especially if the loop order might change right?). 我认为我可以通过使用
useCallback
来阻止这个新的反应钩子功能,但是如果我将它应用于const onClick
那么它仍会在每次渲染时创建一个新实例,因为提供key
参数所需的内联箭头功能,我据我所知,不允许将它应用于循环中的渲染(特别是如果循环顺序可能会改变吗?)。
So how would I go about implementing useCallback
in this scenario while keeping the same functionality? 那么在保持相同功能的同时,如何在这种情况下实现
useCallback
呢? Is it at all possible? 它可能吗?
The simple answer here is, you probably shouldn't use useCallback
here. 这里简单的答案是,你可能不应该在这里使用
useCallback
。 The point of useCallback
is to pass the same function instance to optimized components (eg PureComponent
or React.memo
ized components) to avoid unnecessary rerenders. useCallback
是将相同的函数实例传递给优化的组件(例如PureComponent
或React.memo
组件)以避免不必要的重新渲染。
You're not dealing with optimized components in this case (or most cases, I'd suspect) so there's not really a reason to memoize callbacks like with useCallback
. 在这种情况下你没有处理优化的组件(或者大多数情况下,我怀疑)因此没有理由
useCallback
像useCallback
这样的回调。
Supposing the memoization is important, though, the best solution here is probably to use a single function instead of five: instead of a unique function for each button carries the key
by closure, you can attach the key
to the element: 假设记忆很重要,这里最好的解决方案可能是使用单个函数而不是五个:而不是每个按钮的唯一函数通过闭包来携带
key
,您可以将key
附加到元素:
<button data-key={key}>{key}</button>
And then read the key from the event.target.dataset["key"]
inside a single click handler: 然后在单击处理程序中读取
event.target.dataset["key"]
:
const Example = (props) => { // Single callback, shared by all buttons const onClick = React.useCallback((e) => { // Check which button was clicked const key = e.target.dataset["key"] console.log("You clicked: ", key); }, [/* dependencies */]); return( <div> { _.times(5, (key) => { return ( <button data-key={key} onClick={onClick}> {key} </button> ); }) } </div> ); }; console.log("hello there"); ReactDOM.render(<Example/>, document.getElementById('root'));
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.11/lodash.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script> <div id='root'> </div>
All that being said, it is possible to memoize multiple functions in a single hook. 总而言之,可以在一个钩子中记忆多个功能。
useCallback(fn, deps)
is equivalent to useMemo(() => fn, deps)
, and useMemo
can be used to memoize multiple functions at once: useCallback(fn, deps)
等同于useMemo(() => fn, deps)
, useMemo
可用于一次useMemo
多个函数:
const clickHandlers = useMemo(() => _.times(5, key =>
() => console.log("You clicked", key)
), [/* dependencies */]);
const Example = (props) => { const clickHandlers = React.useMemo(() => _.times(5, key => () => console.log("You clicked", key) ), [/* dependencies */]) return( <div> { _.times(5, (key) => { return ( <button onClick={clickHandlers[key]}> {key} </button> ); }) } </div> ); }; console.log("hello there"); ReactDOM.render(<Example/>, document.getElementById('root'));
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.11/lodash.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script> <div id='root'> </div>
Perhaps there's a case where that's useful, but in this case I would either leave it alone (and not worry about the optimization) or else use a single handler for each button. 也许有一种情况,这是有用的,但在这种情况下,我要么不管它(而不是担心优化)或者为每个按钮使用一个处理程序。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.