根据React文档,当组件挂载(使用DOM元素的值)和卸载(使用null)时调用回调引用:
React将使用DOM元素调用ref回调组件挂载,并在卸载时使用null调用。
根据React调和的文档,当遇到相同类型的DOM元素时,将更新而不是替换:
当比较两个相同类型的React DOM元素时,React会查看两者的属性,保持相同的底层DOM节点,并且只有更新更改的属性。
在下面的简单代码片段中,我们记录了每次回调ref被调用时的日志:
import { useState } from "react";
export default function App() {
const [num, setNum] = useState(0);
return (
<div>
<table ref={(ref) => console.log(ref)}>
<tbody>
<tr>
<td>{num}</td>
</tr>
</tbody>
</table>
<button onClick={() => setNum((prev) => prev + 1)}>Click</button>
</div>
);
}
…令人惊讶的是,每次组件渲染时都会调用它,这表明每次组件渲染时连接的DOM节点也被卸载和加载。
为什么会这样?似乎我不理解文档,或者这里有一些我想理解的其他机制在起作用。
代码沙箱:https://codesandbox.io/s/table-mount-unmount-lr10wv
调用它是因为您将callback作为匿名函数传递,该函数将在每次更新状态时重新创建(从而强制呈现),并且当ref
获得新值(使用新引用重新计算函数)时,它将触发回调执行。可以通过稳定ref回调引用来避免这种情况,如下所示:
import { useCallback, useState } from "react";
export default function App() {
const [num, setNum] = useState(0);
const refCallback = useCallback((ref) => console.log(ref), []);
return (
<div>
<table ref={refCallback}>
<tbody>
<tr>
<td>{num}</td>
</tr>
</tbody>
</table>
<button onClick={() => setNum((prev) => prev + 1)}>Click</button>
</div>
);
}