![](/img/trans.png)
[英]Eslint React Hooks Error: eslint-plugin-react-hooks exhaustive deps warning for a function dependency in useEffect
[英]React hooks function dependency
我发现自己处于一个奇怪的境地。 我正在实施一个钩子,但我无法实现我想要的。
我有这样的事情:
const appHook = props => {
const [foo, setFoo] = React.useState([]);
const [bar, setBar] = React.useState([]);
React.useEffect(() => {
setFoo(getFoo(props.fooList, props.fooId));
setBar(getBar(foo.listToFilter));
}, [props.fooId]);
const getCurrentBlockTrade = (arrayToFilter, number) =>
arrayToFilter.filter(array => array.id === number);
const getSubOutList = (...) => {
...
};
return (<div>something</div>)
}
我的问题是函数 setFoo 被正确执行,所以 foo state 是一个新数组,但取决于 foo 状态的 setBar 接收一个空数组。 基本上 setBar 在 setFoo 完成之前执行,因此 getBar 函数接收一个空数组。
管理这种依赖的正确方法是什么?
谢谢,F。
TL; 博士; 您的解决方案可能是kind user
的回答
下面我将描述我迄今为止在整个研究中的想法和学到的东西,并从人们那里提出 5 条建议/解决方案,通过博客,...
你说过:
我的问题是函数 setFoo 被正确执行,所以 foo state 是一个新数组,但取决于 foo 状态的 setBar 接收一个空数组。 基本上setBar 在 setFoo 完成之前执行,因此 getBar 函数接收一个空数组。
你是真的。 基本上是因为在 React(Hook 和类组件)中, setState
是异步的。 这是什么意思? 这意味着 setSomething 只是告诉 React稍后重新渲染组件。 它不会神奇地替换当前运行函数中的const something
变量——这是不可能的。
const [foo, setFoo] = useState(0)
function handleClick() {
setFoo(42)
// we declared foo with const, you "obviously" shouldn't expect this
// to "somehow" immediately change `foo` to 42
console.log(foo);
// it's 0 in this render, BUT on next render, `foo` will be 42
}
对您来说,最简单的技术是将新计算的foo
值存储在一个变量中,然后将该新计算的值用于 setFoo 和 setBar - 这是一种非常流行的技术。
React.useEffect(() => {
const newFoo = getFoo(props.fooList, props.fooId);
setFoo(newFoo);
setBar(getBar(newFoo.listToFilter));
}, [props.fooId]);
// or: shouldn't use this, only to demonstrate the callback syntax in
// the new setState Hook (different than the old callback syntax setState):
React.useEffect(() => {
setFoo(() => {
const newFoo = getFoo(props.fooList, props.fooId);
setBar(getBar(newFoo.listToFilter));
return newFoo;
})
}, [props.fooId]);
另一种技术可以在这里找到: https : useEffect
正在使用useEffect
来setBar
与foo
的依赖项列表。
React.useEffect(() => {
setFoo(getFoo(props.fooList, props.fooId));
}, [props.fooId]);
React.useEffect(() => {
setBar(getBar(foo.listToFilter));
}, [foo]);
尽管答案获得了 27 票,但我认为这只是使情况过于复杂,而且(据我所知)使组件不必要地重新渲染 2 次而不是 1次,应该避免。
另一个可能有效的解决方案是使用async/await
使状态更改异步触发,以导致更改不被批处理(关于这个答案https://stackoverflow.com/a/53048903/9787887 )
React.useEffect(async () => {
await setFoo(getFoo(props.fooList, props.fooId));
await setBar(getBar(foo.listToFilter));
}, [props.fooId]);
// no, actually this will not work!! it'll throw you an (annoyed) error
// the actual working code is:
React.useEffect(() =>
const setFooAndBar = async () => {
await setFoo(getFoo(props.fooList, props.fooId));
await setBar(getBar(foo.listToFilter));
}
setFooAndBar();
}, [props.fooId]);
你看,工作代码又是另一个过于复杂(和糟糕)的解决方案,(但无论如何都应该引入??)。
gaearon提到的另一个解决方案是使用useReducer
- 使用 Hooks,您还可以使用 Reducer 来集中状态更新逻辑并避免这个陷阱。
他的另一个见解:
- 推荐的解决方案是使用一个变量而不是两个变量(因为一个变量似乎可以从另一个变量计算出来),或者先计算下一个值,然后一起使用它来更新它们。 或者,如果您准备好进行跳跃,useReducer 有助于避免这些陷阱。
但这似乎又是对本案的另一个过于复杂的建议,不是吗?
最后一个建议是gaearon的评论,告诉你重新思考你的状态依赖,状态依赖真的需要吗?
最好的解决方案就是不要有从另一个状态计算出来的状态。 如果
this.state.y
总是从this.state.x
计算出来,this.state.y
完全删除this.state.y
,只跟踪this.state.x
。 并计算渲染时所需的内容
感谢您有足够的耐心阅读到这里:))。
setState
是一个异步函数,这就是您在setBar
函数中收到一个空数组的setBar
。 基本上你不能确定状态会在第二个setState
评估之前更新。
为什么不在这两种情况下都简单地引用 props 呢?
React.useEffect(() => {
const newFoo = getFoo(props.fooList, props.fooId);
setFoo(newFoo);
setBar(getBar(newFoo.listToFilter));
}, [props.fooId]);
设置状态是一个异步过程。 所以setBar(getBar(foo.listToFilter));
调用这个 foo 是空数组。 您可以为此使用另一个 useEffect
React.useEffect(() => {
setFoo(getFoo(props.fooList, props.fooId));
}, [props.fooId]);
React.useEffect(() => {
setBar(getBar(foo.listToFilter));
}, [foo]);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.