React 钩子函数依赖 [英] React hooks function dependency

查看:76
本文介绍了React 钩子函数依赖的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我发现自己处于一个奇怪的境地.我正在实施一个钩子,但我无法实现我想要的.

I am finding myself in a weird situation. I am implementing an hook and I cannot manage to achieve what I want.

我有这样的事情:

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 函数接收一个空数组.

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. Basically setBar is executed before setFoo finished so the getBar function receives an empty array.

管理这种依赖的正确方法是什么?

What is the right way to manage this kind of dependency?

谢谢,F.

推荐答案

TL;DR; 您的解决方案可能是 好心用户的回答

TL;DR; Your solution is likely kind user's answer

下面我将描述我迄今为止在整个研究过程中的想法和学到的东西,并从人们、通过博客、...提出5 条建议/解决方案...

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,...

你说过:

我的问题是函数 setFoo 被正确执行,所以 foo state 是一个新数组,但是依赖于 foo 状态的 setBar 接收一个空数组.基本上 setBar 在 setFoo 完成之前执行,因此 getBar 函数接收一个空数组.

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. Basically setBar is executed before setFoo finished so the getBar function receives an empty array.

你说得对.基本上是因为在 React(Hooks 和类组件)中,setState 是异步的.这是什么意思?这意味着 setSomething 只是告诉 React 稍后重新渲染组件.它不会神奇地替换当前运行函数中的 const something 变量——这是不可能的.

You're true. Basically because in React (both Hooks and class component), setState is asynchronous. What does it mean? It means that setSomething just tells React to re-render the component later. It doesn't magically replace the const something variable in the current running function — that's not possible.

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
}

<小时>

解决方案 1.

对您来说,最简单的技术是将 foo 的新计算值存储在一个变量中,然后将新计算的值用于 setFoo 和 setBar - 这是一种非常流行的技术.


Solution 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.

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

<小时>

解决方案 2.

另一种技术可以在这里找到:https://stackoverflow.com/a/54120692/9787887 正在使用 useEffectsetBarfoo 的依赖列表.


Solution 2.

Another technique can be found here: https://stackoverflow.com/a/54120692/9787887 is using useEffect to setBar with the dependency list whose foo.

React.useEffect(() => {
    setFoo(getFoo(props.fooList, props.fooId));
}, [props.fooId]);

React.useEffect(() => {
    setBar(getBar(foo.listToFilter));
}, [foo]);

尽管答案获得了 27 票,但我认为这只是使情况过于复杂,而且(据我所知)应该避免使组件不必要地重新渲染 2 次而不是 1 次.

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.

另一个可能有效的解决方案是使用 async/await 使状态更改异步触发,从而导致更改不被批处理(关于这个答案 https://stackoverflow.com/a/53048903/9787887)

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)

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??).

gaearon 提到的另一种解决方案 是使用 useReducer

Another solution that gaearon mentioned is to use useReducer

  • 借助 Hook,您还可以使用 Reducer 来集中状态更新逻辑并避免这种陷阱.

他的另一个见解:

  • 推荐的解决方案是使用一个变量而不是两个变量(因为一个变量似乎可以从另一个变量计算出来),或者先计算下一个值,然后一起使用它来更新它们.或者,如果您已准备好进行跳跃,useReducer 有助于避免这些陷阱.

但对于这个案例,这似乎又是另一个过于复杂的建议,不是吗?

But it again seems to be another overcomplex suggestion to this case, doesn't it?

最后的建议是gaearon 的评论,告诉你重新考虑你的状态依赖,状态依赖真的需要吗?

The last suggestion is a comment of gaearon, tell you to rethink about your state dependence, is the state dependence really needed?

最好的解决方案就是不要有从另一个状态计算出来的状态.如果 this.state.y 总是从 this.state.x 计算,完全删除 this.state.y,并且只跟踪 this.state.x. 并计算渲染时所需的内容

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. And calculate what you need when rendering instead

<小时>

感谢您有足够的耐心读到这里:))


Thank you for being patient enough to read to here :)).

这篇关于React 钩子函数依赖的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆