简体   繁体   English

React 钩子函数依赖

[英]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
}

Solution 1.解决方案1。

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]);

Solution 2.解决方案 2。

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正在使用useEffectsetBarfoo的依赖项列表。

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,应该避免。


Solution 3.解决方案 3。

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??).你看,工作代码又是另一个过于复杂(和糟糕)的解决方案,(但无论如何都应该引入??)。


Solution 4.解决方案 4。

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?但这似乎又是对本案的另一个过于复杂的建议,不是吗?


Solution 5.解决方案 5。

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 from this.state.x , remove this.state.y completely, and only track this.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.

相关问题 Eslint React Hooks错误:eslint-plugin-react-hooks用尽详尽的警告警告useEffect中的功能依赖项 - Eslint React Hooks Error: eslint-plugin-react-hooks exhaustive deps warning for a function dependency in useEffect React hooks useMemo, false 作为依赖 - React hooks useMemo, false as dependency React hooks map 不是函数 - React hooks map is not a function React Hooks:为什么exhaustive-deps linter 规则要在依赖列表中的useMemo 中使用本地函数? - React Hooks: Why does the exhaustive-deps linter rule want a local function used in useMemo in the dependency list? React hooks:当我们尝试调用一个函数时,useMemo 和 useEffect 有一个 Missing 依赖 - React hooks : useMemo and useEffect has a Missing dependency when we are trying to call a function 如果我需要更新 2 个依赖变量,React 如何只执行一次副作用函数 - React hooks how to only execute side effect function only once if I need to update 2 dependency variables 如果发现更改,则挂钩依赖 API 调用 React - Hooks dependency API call if changes found React 同一依赖项的多个 React 效果挂钩 - Multiple React effect hooks for the same dependency React Hooks:将对象作为 useEffects 中的依赖项处理 - React Hooks: Handling Objects as dependency in useEffects React hooks:如何摆脱 state 依赖 - React hooks: how to get rid of a state dependency
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM