当前位置: 首页 > 知识库问答 >
问题:

React钩子函数依赖

云和硕
2023-03-14

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

我有这样的想法:

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是一个新的数组,但是setBar依赖于foo的状态,接收一个空数组。基本上setBar是在setFoo完成之前执行的,所以getBar函数接收一个空数组。

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

谢谢F

共有3个答案

洪星文
2023-03-14

setState是一个异步函数,这就是为什么在setBar函数中接收到一个空数组的原因。基本上,您不能确定状态是否会在第二个setState计算之前更新。

为什么不在这两种情况下简单地参考道具呢?

React.useEffect(() => {
   const newFoo = getFoo(props.fooList, props.fooId);

   setFoo(newFoo);
   setBar(getBar(newFoo.listToFilter));
}, [props.fooId]);
邴兴为
2023-03-14

设置状态是一个异步过程。SosetBar(getBar(foo.listToFilter)) 调用此foo的是空数组。您可以为此使用另一个useEffect

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



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

郤飞英
2023-03-14

TL;博士您的解决方案可能是善良用户的回答

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

你说过:

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

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

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://stackoverflow.com/a/54120692/9787887 正在对其foo的依赖项列表使用useffectsetBar

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提到的另一个解决方案是使用useReduer

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

另一个例子是他的见解:

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

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

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

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

谢谢你有足够的耐心读到这里:))。

 类似资料:
  • 其默认“BDD”式接口,mocha提供钩before(),after(),beforeEach(),和afterEach()。这些应该用于设置前置条件并在测试后进行清理。 describe('hooks', function() { before(function() { // runs before all tests in this block }); after(function() {

  • 问题:在函数“selectmenu”中调用了React钩子“React.useEffect”,该函数既不是React函数组件,也不是自定义React钩子函数 目标:我只想在单击按钮时挂载组件('Component DidMount/WillUnmount)(使用useffect()),而不是在加载文件(或整个组件)时挂载 实际目标:我想在单击时选择(或突出显示)一个文件(自定义)。但是,当用户在文

  • 我试图在一个功能组件中调用一个API,它是一个反应挂钩,并基于结果,重新呈现组件的内容。下面是代码: 调用API的组件- 以下是功能: 我正在尝试获取状态数据,并根据数据重新渲染组件。这里处于调用外部API的操作中。 正在调用操作并成功获取数据,但我不确定为什么状态正在更新-我得到了以下错误- 在函数“setResults”中调用React钩子“useState”,该函数既不是React函数组件,

  • 我在useeffect钩子上得到以下错误。 React Hook use效应有一个缺失的依赖项:当前页面。要么包含它,要么删除依赖array.eslintreact-钩子/穷举-deps 你知道我为什么会得到这个吗? }

  • 空闲任务钩子函数 空闲任务在执行时可以选择是否回调一个钩子函数,空闲任务运行在系统的最低优先级上,因此只有在应用程序任务全部处在阻塞或挂起态时,空闲任务才会得到执行。这使得可以使用空闲任务的钩子函数将系统转入低功耗模式,或者做一些其他任务。 使用空闲任务的钩子函数,需要将configUSE_IDLE_HOOK设置为1.并且,空闲任务钩子函数需要申明为如下原型: void vApplicationI

  • 一个指令定义对象可以提供如下几个钩子函数 (均为可选): bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。 inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。 update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽