【发布时间】:2019-07-31 13:47:51
【问题描述】:
我有上下文消费者组件,它们位于提供者组件下方,提供者组件将功能向下传递到上下文中。
我正在尝试从上下文中运行一个“设置”函数,该函数通过传递到上下文中的函数向父级注册一个子级。
似乎所有组件都触发了状态更改,但只有模板中声明的最后一个组件的更改保持不变。
为什么会这样?
【问题讨论】:
标签: reactjs
我有上下文消费者组件,它们位于提供者组件下方,提供者组件将功能向下传递到上下文中。
我正在尝试从上下文中运行一个“设置”函数,该函数通过传递到上下文中的函数向父级注册一个子级。
似乎所有组件都触发了状态更改,但只有模板中声明的最后一个组件的更改保持不变。
为什么会这样?
【问题讨论】:
标签: reactjs
您的代码中存在某种竞争条件。
const addItem = (item: string) => {
setItems([...items, item])
}
这部分被 3 个不同的组件调用。但是设置状态不是顺序的。 所有三个调用都试图将状态设置为
[...[], 'one']
[...[], 'two']
[...[], 'three']
因此你得到了你的结果。它们都依赖于初始状态,而它们应该依赖于先前的状态。
解决办法如下:
const addItem = (item: string) => {
setItems(prevItems => [...prevItems, item])
}
编辑 - 第一种方法发生了什么? 一旦组件安装,React 会安排 3 个 setState 调用。当组件挂载时,项目状态为 []。所以所有预定的调用都在尝试使用以下值修改状态:
[...[], 'one']
[...[], 'two']
[...[], 'three']
也许您的组件的生命周期更清楚:
- 渲染框
- 渲染项目一
- 渲染项目二
- 渲染项目三
(此时项目状态为 [])
- 项目一的效果setState([...[], 'one'])
- 项目二的效果setState([...[], 'two'])
- 项目三效果setState([...[], 'three'])
- 物品状态更改为[...[], 'one']
- 物品状态更改为[...[], 'two']
- 物品状态更改为[...[], 'three']
- 再次渲染并查看结果
解决方案的生命周期是什么:
- 渲染框
- 渲染项目一
- 渲染项目二
- 渲染项目三
(此时项目状态为 [])
- 项目一的效果setState(prevItems => [...prevItems, 'one'])
- 项目二的效果setState(prevItems => [...prevItems, 'two'])
- 项目三效果setState(prevItems => [...prevItems, 'three'])
- 物品状态更改为[...[], 'one']
- 物品状态更改为[...['one'], 'two']
- 物品状态更改为[...['one', 'two'], 'three']
- 再次渲染并查看结果
重点是,当您调用 setState 方法时,它不是同步的,因此不会立即发生更改。这就是为什么您可以选择通过传递回调函数来根据之前的状态更改状态
当setState(callbackFn) 被执行时,react 会知道你正在尝试根据前一次构造新的状态。
因此,每当您更新状态时,您应该考虑是否根据新状态设置新状态。如果是这样,您应该使用带有回调而不是值的 setState 函数
【讨论】: