[英]React hooks function dependency
I am finding myself in a weird situation.我发现自己处于一个奇怪的境地。 I am implementing an hook and I cannot manage to achieve what I want.
我正在实施一个钩子,但我无法实现我想要的。
I have something like this:我有这样的事情:
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>)
}
My issue is that the function setFoo is properly executed, so foo state is a new array, but setBar that depends on the state of foo, receives an empty array.我的问题是函数 setFoo 被正确执行,所以 foo state 是一个新数组,但取决于 foo 状态的 setBar 接收一个空数组。 Basically setBar is executed before setFoo finished so the getBar function receives an empty array.
基本上 setBar 在 setFoo 完成之前执行,因此 getBar 函数接收一个空数组。
What is the right way to manage this kind of dependency?管理这种依赖的正确方法是什么?
Thanks, F.谢谢,F。
TL;DR; TL; 博士; Your solution is likely
kind user
's answer您的解决方案可能是
kind user
的回答
Below I'll describe what I've thought and learned so far throughout researches, and come up with 5 suggestions/solutions from people, via blogs,...下面我将描述我迄今为止在整个研究中的想法和学到的东西,并从人们那里提出 5 条建议/解决方案,通过博客,...
You've said:你说过:
My issue is that the function setFoo is properly executed, so foo state is a new array, but setBar that depends on the state of foo, receives an empty array.
我的问题是函数 setFoo 被正确执行,所以 foo state 是一个新数组,但取决于 foo 状态的 setBar 接收一个空数组。 Basically setBar is executed before setFoo finished so the getBar function receives an empty array .
基本上setBar 在 setFoo 完成之前执行,因此 getBar 函数接收一个空数组。
You're true.你是真的。 Basically because in React (both Hooks and class component),
setState
is asynchronous.基本上是因为在 React(Hook 和类组件)中,
setState
是异步的。 What does it mean?这是什么意思? It means that setSomething just tells React to re-render the component later .
这意味着 setSomething 只是告诉 React稍后重新渲染组件。 It doesn't magically replace the
const something
variable in the current running function — that's not possible.它不会神奇地替换当前运行函数中的
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
}
The easiest technique to you is to store the newly calculated value of foo
in a variable, then use that newly calculated value to both setFoo and setBar - a quite popular technique tho.对您来说,最简单的技术是将新计算的
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]);
Another technique can be found here: https://stackoverflow.com/a/54120692/9787887 is using useEffect
to setBar
with the dependency list whose foo
.另一种技术可以在这里找到: https :
useEffect
正在使用useEffect
来setBar
与foo
的依赖项列表。
React.useEffect(() => {
setFoo(getFoo(props.fooList, props.fooId));
}, [props.fooId]);
React.useEffect(() => {
setBar(getBar(foo.listToFilter));
}, [foo]);
Despite the answer get 27 upvotes, I think it's just overcomplicated the situation, and also (as I know) make the component unnecessarily rerender 2 times instead of 1, should be avoided.尽管答案获得了 27 票,但我认为这只是使情况过于复杂,而且(据我所知)使组件不必要地重新渲染 2 次而不是 1次,应该避免。
Another solution that might work is to use async/await
to make the state changes triggered asynchronously, to lead the changes not be batched (regarding this answer https://stackoverflow.com/a/53048903/9787887 )另一个可能有效的解决方案是使用
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]);
You see, the working code is again another overcomplicated (and bad) solution, (but should be introduced anyway??).你看,工作代码又是另一个过于复杂(和糟糕)的解决方案,(但无论如何都应该引入??)。
Another solution that gaearon mentioned is to use useReducer
gaearon提到的另一个解决方案是使用
useReducer
- With Hooks you could also useReducer to centralize state update logic and avoid this pitfall.
使用 Hooks,您还可以使用 Reducer 来集中状态更新逻辑并避免这个陷阱。
Another his insight:他的另一个见解:
- the recommended solution is to either use one variable instead of two (since one can be calculated from the other one, it seems), or to calculate the next value first and update them both using it together.
推荐的解决方案是使用一个变量而不是两个变量(因为一个变量似乎可以从另一个变量计算出来),或者先计算下一个值,然后一起使用它来更新它们。 Or, if you're ready to make the jump, useReducer helps avoid these pitfalls.
或者,如果您准备好进行跳跃,useReducer 有助于避免这些陷阱。
But it again seems to be another overcomplex suggestion to this case, doesn't it?但这似乎又是对本案的另一个过于复杂的建议,不是吗?
The last suggestion is a comment of gaearon , tell you to rethink about your state dependence , is the state dependence really needed?最后一个建议是gaearon的评论,告诉你重新思考你的状态依赖,状态依赖真的需要吗?
the best solution is simply to not have state that is calculated from another state.
最好的解决方案就是不要有从另一个状态计算出来的状态。 If
this.state.y
is always calculated fromthis.state.x
, removethis.state.y
completely, and only trackthis.state.x
.如果
this.state.y
总是从this.state.x
计算出来,this.state.y
完全删除this.state.y
,只跟踪this.state.x
。 And calculate what you need when rendering instead并计算渲染时所需的内容
Thank you for being patient enough to read to here :)).感谢您有足够的耐心阅读到这里:))。
setState
is an asynchronous function, that's why you are receiving an empty array in setBar
function. setState
是一个异步函数,这就是您在setBar
函数中收到一个空数组的setBar
。 Basically you can't be sure that the state will be updated before the second setState
evaluates.基本上你不能确定状态会在第二个
setState
评估之前更新。
Why not to simply refer to the props in both cases?为什么不在这两种情况下都简单地引用 props 呢?
React.useEffect(() => {
const newFoo = getFoo(props.fooList, props.fooId);
setFoo(newFoo);
setBar(getBar(newFoo.listToFilter));
}, [props.fooId]);
Setting a state is an asynchronus process.设置状态是一个异步过程。 So
setBar(getBar(foo.listToFilter));
所以
setBar(getBar(foo.listToFilter));
calling this foo is the empty array.调用这个 foo 是空数组。 You can use another useEffect for this
您可以为此使用另一个 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.