我写了下面的 React 练习,它不使用钩子并渲染一个按钮。
const Button = ({ onClick }) => <button onClick={onClick}>Do Nothing</button>;
const Base = () => {
const onClickFunction = (() => {
console.log("Creating OnClick Function");
return () => {};
})();
return (
<div className="App">
<h1>Hello</h1>
<Button onClick={onClickFunction} />
</div>
);
};
onClickFunction 使用自调用函数,因此我可以放置一个console.log
来查看以下行为。 在此示例中,呈现 Base 时,消息">创建 OnClick 函数"仅出现一次 👍
但是,如果我将Base
更改为以下内容,请添加钩子用法:
const Button = ({ onClick }) => <button onClick={onClick}>Do Nothing</button>;
const Base = () => {
const notUsedRef = React.useRef();
const onClickFunction = (() => {
console.log("Creating OnClick Function");
return () => {};
})();
return (
<div className="App">
<h1>Hello</h1>
<Button onClick={onClickFunction} />
</div>
);
};
您将看到两次"创建 OnClick 函数"消息。
这个代码沙盒说明了我所看到的:https://codesandbox.io/s/dawn-forest-99clo?file=/src/App.js
- 使用 React DevTools Profiler,我们可以看到没有重新渲染此组件。
- 使用
<React.Profiler
,它报告此组件也没有更新。
我知道使用React.useCallback
不会触发第二次调用,但是问题仍然存在,为什么我们处于 Base 被调用两次的情况。
我的问题是:当不需要重新渲染时,为什么以及什么触发要调用的 Base。
这是由于 React 实现钩子的方式。 如果你调用任何钩子,即使你不使用结果值,你也会告诉 React 在挂载之前渲染两次,即使 props 没有改变。你可以用useState、useEffect等来代替useRef的用法,试试下面的方法。
你也可以用 React.memo 包装你的组件。函数内定义的每个函数都会在每次渲染中重新创建。
https://codesandbox.io/s/elastic-water-y18w0?file=/src/App.js
编辑:仅在开发过程中和由React.StrictMode包装的组件中发生。用盖龙的话说:
这是严格模式的一个有意功能。这只发生在 发展,并帮助发现意外的副作用放入 渲染阶段。我们只对带有 Hook 的组件执行此操作,因为这些组件 更有可能在错误的地方意外产生副作用。
https://github.com/facebook/react/issues/15074