我发现自己处于一种奇怪的境地。我正在实现一个钩子,我无法实现我想要的。
我有这样的想法:
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
setState是一个异步函数,这就是为什么在setBar函数中接收到一个空数组的原因。基本上,您不能确定状态是否会在第二个setState
计算之前更新。
为什么不在这两种情况下简单地参考道具呢?
React.useEffect(() => {
const newFoo = getFoo(props.fooList, props.fooId);
setFoo(newFoo);
setBar(getBar(newFoo.listToFilter));
}, [props.fooId]);
设置状态是一个异步过程。SosetBar(getBar(foo.listToFilter))
调用此foo的是空数组。您可以为此使用另一个useEffect
React.useEffect(() => {
setFoo(getFoo(props.fooList, props.fooId));
}, [props.fooId]);
React.useEffect(() => {
setBar(getBar(foo.listToFilter));
}, [foo]);
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
的依赖项列表使用useffect
到setBar
。
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
另一个例子是他的见解:
但这似乎又是另一个过于复杂的建议,不是吗?
最后一个建议是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 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽