繁体   English   中英

React 钩子函数依赖

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

解决方案1。

对您来说,最简单的技术是将新计算的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]);

解决方案 2。

另一种技术可以在这里找到: https : useEffect正在使用useEffectsetBarfoo的依赖项列表。

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

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

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


解决方案 3。

另一个可能有效的解决方案是使用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]);

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


解决方案 4。

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

  • 使用 Hooks,您还可以使用 Reducer 来集中状态更新逻辑并避免这个陷阱。

他的另一个见解:

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

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


解决方案 5。

最后一个建议是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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM