我经常通过React回调来面对这种情况:
const MyComponent = ({ onLoad }) => {
useEffect => {
// some stuff
onLoad(/* args */);
}, [onLoad]);
return (<div />);
}
问题是。我认为我的组件只能加载一次。使用useEffect时,我必须在依赖项中设置onLoad,这会导致对onLoad属性的任何更改以触发效果。
我通常会用裁判来解决这个问题
const MyComponent = ({ onLoad: _onLoad }) => {
const onLoadRef = useRef(_onLoad);
onLoadRef.current = _onLoad;
useEffect => {
// some stuff
onLoadRef.current(/* args */);
}, []); // No dependencies anymore
return (<div />);
}
它运作良好并解决了许多类似的问题,但是我觉得它有点丑陋,而且对初学者并不友好。我想知道是否有更好的解决方案,或者我做的是反模式吗?
答案 0 :(得分:2)
根据上面的评论:这是如何使用useEffect的好资源 https://reacttraining.com/blog/useEffect-is-not-the-new-componentDidMount/
本文专门强调了为什么您需要与类组件生命周期方法不同地考虑useEffect的主要原因。
我们经常在组件首次安装时进行一些设置,例如 网络通话或订阅。我们已经学会了思考 用诸如componentDidMount()之类的“时刻”的术语, componentDidUpdate()和componentWillUnmount()。很自然 了解React的先验知识,并在钩子中寻求1:1的等效项。一世 我自己做了,我想每个人都先做。很多时候我会 在我的工作室中听到...
“相当于[某些生命周期方法]的钩子是什么?”
快速的回答是,钩子是从思考的范式转变 用“生命周期和时间”来思考“状态和时间” 与DOM同步”。尝试采用旧的范例并应用 只是钩子效果不好,会阻碍您前进。
它也很好地介绍了useEffect,并提供了从类组件转换为钩子的示例。
另一个好消息来源是Dan Abramov的https://overreacted.io/a-complete-guide-to-useeffect/。即使阅读时间很长,我也绝对推荐这样做。当我第一次开始使用钩子以正确的方式思考它们时,这确实对我有帮助。
这是本文开头的一小段摘录。
但是有时候当您使用效果时,这些部分并不能很好地融合在一起。 您有missing漏的感觉,想念一些东西。它似乎 类似于类的生命周期……但这是真的吗?你发现自己 问类似的问题
?如何使用useEffect复制componentDidMount?
?如何正确获取useEffect中的数据?什么是[]?
?是否需要将功能指定为效果依赖项?
?为什么有时有时会得到无限的重访循环?
?为什么有时我的效果中会出现旧状态或道具值?
当我刚开始使用Hooks时,所有这些让我感到困惑 也有问题。即使在编写初始文档时,我也没有 牢牢把握一些微妙之处。从那以后我有一些“啊哈” 我想与你分享的时刻这种深潜将使 这些问题的答案对您来说很明显。
要查看答案,我们需要退后一步。这个目标 文章不是要给您列出要点食谱。是为了帮助 您真正地“咆哮”了useEffect。没什么可学的。事实上, 我们将花费大部分时间进行学习。
只有在我停止通过浏览器查看useEffect Hook之后 熟悉的类生命周期方法的棱镜,一切都来了 为我在一起。
就上述原始问题而言,使用refs是一个很好的方法,可以使您的效果不具有特定的函数和值作为依赖项。
如果您“要在效果中定义的某些回调中读取最新值而不是捕获的值”,则它们特别好
对于海报中的示例:
const MyComponent = ({ onLoad: _onLoad }) => {
const onLoadRef = useRef(_onLoad);
onLoadRef.current = _onLoad;
useEffect => {
// some stuff
onLoadRef.current(/* args */);
}, []); // No dependencies anymore
return (<div />);
}
这是一种完全有效的处理方式,尽管取决于onLoad所使用的参数及其工作方式,将额外的项添加到依赖项数组以使其始终保持同步可能是个好主意。
您可以在此处抽象出useRef的含义,但不幸的是,钩子eslint插件的规则无法将其识别为ref。它将起作用,您只需要将onLoadRef添加到依赖项数组中即可,尽管它永远不会导致效果重新运行。类似于从react-redux派发之类的事情,您知道它很稳定,但是eslint插件不知道。
function useRefUpdater(value) {
const ref = useRef(value);
// I forget where I saw that you should change the ref in a useEffect
useEffect(() => {
ref.current = value;
}, [value]);
return ref;
}
const MyComponent = ({ onLoad: _onLoad }) => {
const onLoadRef = useRefUpdater(_onLoad)
useEffect(() => {
// some stuff
onLoadRef.current(/* args */);
}, []);
// React Hook useEffect has a missing dependency: 'onLoadRef'. Either include it or remove the dependency array.
return <div />;
};