英文:
React ref callbacks behaves differently with useCallback hook?
问题
在我的React组件中,使用了类似下面这样的useCallback
钩子。我使用useCallback
包装了一个onClick
事件处理程序,并使用useCallback
包装了一个ref
回调函数。在单击按钮时,会更改状态值,从而导致组件重新渲染。观察到在onClick
事件处理程序"handleOnClick"内部的控制台日志在每次重新渲染时都会执行,而在ref
回调函数"divRefCallback"内部的控制台日志只执行一次。
我可以理解为什么"handleOnClick"在每次重新渲染时都会执行,因为useCallback
只会避免重新创建函数,但不会避免重新执行函数。然而,我不能理解为什么useCallback
在处理ref
回调时表现不同,因为在这个示例中,它既不重新创建函数,也不执行回调内部的逻辑。
我想知道为什么它会表现成这样?是否有其他情况下,useCallback
会避免重新执行回调逻辑?
是否有官方文档可以解释这个问题?提前感谢任何见解!
function UseCallbackDemo() {
const divRef = React.useRef<HTMLDivElement | null>(null);
const [count, setCount] = React.useState(0);
console.log("**** 重新渲染组件");
const divRefCallback = React.useCallback((div) => {
if (div) {
divRef.current = div;
}
console.log("*** divRefCallback");
}, []);
const handleOnClick = React.useCallback(() => {
console.log('**** handleOnClick');
setCount(count => count + 1);
}, []);
return (
<>
<div ref={divRefCallback}>{count}</div>
<button onClick={handleOnClick}>点击</button>
</>
);
}
请在这里测试代码:https://playcode.io/1529685
英文:
In my React component with useCallback hook like below. I wrapped a onClick event handler with useCallback also wrapped a ref callback with useCallback. While clicking on the button, it would change the state value hence cause the component to re-render. It's observed that the console log inside the onClick event handler "handleOnClick" is executed at every re-render, whereas the console log inside the ref callback "divRefCallback" only executed once.
I can understand why the handleOnClick is executed at each re-render, because useCallback will only avoid recreating the function, but will NOT avoid re-executing the function. However, I cannot understand why useCallback works differently with ref callback, because in this example, it doesn't re-create the function but also not executing the logic inside the callback as well.
I am wondering why it's behaving like this? Is there any other scenario where useCallback would avoid re-executing the callback logic?
Is there any official document to explain this? Thanks in advance for any insights!
function UseCallbackDemo() {
const divRef = React.useRef<HTMLDivElement | null>(null);
const [count, setCount] = React.useState(0);
console.log("**** re-render component");
const divRefCallback = React.useCallback((div) => {
if (div) {
divRef.current = div;
}
console.log("*** divRefCallback");
}, []);
const handleOnClick = React.useCallback(() => {
console.log('**** handleOnClick');
setCount(count => count + 1);
}, []);
return (
<>
<div ref={divRefCallback}>{count}</div>
<button onClick={handleOnClick}>click</button>
</>
);
}
Please test the code here: https://playcode.io/1529685
答案1
得分: 2
根据文档:
<blockquote>
不要使用 ref 对象(类似于由 <code>useRef</code> 返回的对象),可以将函数传递给 ref 属性。<br> <br>
<pre><code><div ref={(node) => console.log(node)} /></code></pre>
当 <div> DOM 节点添加到屏幕时,React 将以 DOM 节点作为参数调用您的 ref 回调函数。当该 <div> DOM 节点被移除时,React 将以 null 调用您的 ref 回调函数。<br> <br>
每当传递不同的 ref 回调时,React 也会调用您的 ref 回调函数。在上面的示例中,<code>(node) => { ... }</code> 每次渲染时都是不同的函数。当您的组件重新渲染时,以前的函数将以 null 作为参数被调用,然后下一个函数将以 DOM 节点作为参数被调用。
</blockquote>
由于 useCallback
在依赖数组为空时每次都返回相同的函数引用,因此在问题示例中,ref 函数仅在 <div>
被移除之前被调用一次。
英文:
According to the documentation:
<blockquote>
Instead of a ref object (like the one returned by <code>useRef</code>), you may pass a function to the ref attribute. <br> <br>
<pre><code><div ref={(node) => console.log(node)} /></code></pre>
When the <div> DOM node is added to the screen, React will call your ref callback with the DOM node as the argument. When that <div> DOM node is removed, React will call your ref callback with null. <br> <br>
React will also call your ref callback whenever you pass a different ref callback. In the above example, <code>(node) => { ... }</code> is a different function on every render. When your component re-renders, the previous function will be called with null as the argument, and the next function will be called with the DOM node.
</blockquote>
Since useCallback
returns the same function reference each time when the dependency array is empty, the ref function is only called once (before the <div>
is removed) in the example from the question.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论