我们必须停止思考组件生命周期方法(例如componentDidMount
)。我们必须开始思考副作用。React的效果与旧式类生命周期方法不同。
默认情况下,每次渲染周期后都会运行效果,但有选项可以选择退出此行为。要选择退出,可以定义依赖项,这意味着只有在对其中一个依赖项进行更改时才执行该效果。
如果您明确定义了一个效果没有任何依赖关系,那么该效果仅在第一个渲染周期后运行一次。
第1个解决方案(带有ESLint警告)
因此,您的示例的第一个解决方案如下:
function MyComponent() {
const loadDataOnlyOnce = () => {
console.log("loadDataOnlyOnce");
};
useEffect(() => {
loadDataOnlyOnce();
}, []);
return (...);
}
但 React Hooks ESLint 插件可能会提示类似以下的错误:
React Hook useEffect has missing dependency: loadDataOnlyOnce. Either include it or remove the dependency array
起初这个警告看起来很烦人,但请不要忽略它。它有助于你更好地编写代码并避免“闭包陈旧”问题。如果你不知道什么是“闭包陈旧”,请阅读这篇优秀的文章.
第二种解决方案(如果依赖项不依赖于组件,则为正确方法)
如果我们将 loadDataOnlyOnce
添加到依赖项数组中,则我们的 effect 将在每个渲染周期后运行,因为在每次渲染时,loadDataOnlyOnce
的引用都会更改。这是因为该函数被销毁(垃圾回收),并创建了一个新的函数,但这恰恰不是我们想要的。
我们必须在渲染周期中保持相同的loadDataOnlyOnce
引用。
所以只需要将函数定义移到上面即可:
const loadDataOnlyOnce = () => {
console.log("loadDataOnlyOnce");
};
function MyComponent() {
useEffect(() => {
loadDataOnlyOnce();
}, [loadDataOnlyOnce]);
return (...);
}
通过这个更改,您可以确保loadDataOnlyOnce
的引用永远不会改变。因此,您也可以将引用安全地添加到依赖项数组中。
第三种解决方案(如果依赖于组件,则为正确方法)
如果效果的依赖性(loadDataOnlyOnce
)依赖于组件(需要props或state),则React内置了useCallback
钩子。
useCallback
钩子的基本意义是在渲染周期内保持函数的引用相同。
function MyComponent() {
const [state, setState] = useState("state");
const loadDataOnlyOnce = useCallback(() => {
console.log(`I need ${state}!!`);
}, [state]);
useEffect(() => {
loadDataOnlyOnce();
}, [loadDataOnlyOnce]);
return (...);
}