我们必须停止思考组件生命周期方法(即componentDidMount)。我们必须开始考虑效果。React效果不同于老式的类-生命周期方法。
默认情况下,效果在每个渲染周期后运行,但也有选择退出这种行为的选项。若要选择退出,可以定义依赖项,这意味着仅在对其中一个依赖项进行更改时才执行效果。
如果显式地定义一个效果没有依赖关系,则该效果只在第一个渲染循环之后运行一次。
第一个解决方案(带有ESLint-complaint)
所以,你的例子的第一个解决方案是:
function MyComponent() {
const loadDataOnlyOnce = () => {
console.log("loadDataOnlyOnce");
};
useEffect(() => {
loadDataOnlyOnce(); // this will fire only on first render
}, []);
return (...);
}
但是React Hooks ESLint插件会抱怨这样的事情:
React钩子useEffect缺少依赖项:loadDataOnlyOnce。要么包含它,要么删除依赖数组。
起初,这个警告似乎很烦人,但请不要忽视它。它可以帮助你更好地编码,并将你从“陈旧的闭包”中拯救出来。如果你不知道什么是“过期闭包”,请阅读这篇很棒的文章。
第二种解决方案(正确的方法,如果依赖关系不依赖于组件)
如果我们将loadDataOnlyOnce添加到依赖数组中,我们的效果将在每次呈现循环后运行,因为loadDataOnlyOnce的引用在每次呈现时都会改变,因为函数被销毁(垃圾回收)并创建一个新函数,但这正是我们不想要的。
我们必须在渲染周期中保持loadDataOnlyOnce的相同引用。
所以只要把函数定义移到上面:
const loadDataOnlyOnce = () => {
console.log("loadDataOnlyOnce");
};
function MyComponent() {
useEffect(() => {
loadDataOnlyOnce(); // this will fire only on first render
}, [loadDataOnlyOnce]);
return (...);
}
通过这个更改,您可以确保loadDataOnlyOnce的引用永远不会改变。因此,您还可以安全地将引用添加到依赖项数组中。
第三种解决方案(正确的方法,如果依赖依赖于组件)
如果效果的依赖关系(loadDataOnlyOnce)依赖于组件(需要道具或状态),React内置的useCallback-Hook。
useCallback-Hook的基本含义是在呈现循环期间保持函数的引用相同。
function MyComponent() {
const [state, setState] = useState("state");
const loadDataOnlyOnce = useCallback(() => {
console.log(`I need ${state}!!`);
}, [state]);
useEffect(() => {
loadDataOnlyOnce(); // this will fire only when loadDataOnlyOnce-reference changes
}, [loadDataOnlyOnce]);
return (...);
}