简单的例子:我想从牌堆中选择一张牌并将其带到我的手上。当我选择卡片时,我将其附加到“chosenCard”状态。所以,当我选择这张卡时,我想做下一步:
setMyCards(prevState => [...prevState, {...chosenCard}])
setChosenCard(null)
问题是:可以吗?更改状态是异步的,那么第一个函数将在第二个函数之前正常工作是否准确?如果是,为什么?有没有可能,第二个函数可以改变状态,而第一个函数将工作不正确(也许在更复杂的情况下)?
如果我理解正确的话,您担心第二行代码可能会在第一行代码之前生效,从而有效地将
null
值添加到 myCards
。
您可以放心地假设这不会发生。当执行
setMyCards
时,chosenCard
还不会重置为null
。读取第一行中 chosenCard
的值不是异步的,因此代码中后面发生的任何事情都不会产生任何影响。
如果你有相反的执行顺序,你可能会遇到不同的情况:
setChosenCard({ newValue: 42 })
setMyCards(prevState => [...prevState, {...chosenCard}])
在这种情况下,
chosenCard
的新值仅在下一个渲染周期中变得可见,而setMyCards
还不会拾取它。
有不同的方法来处理这个问题:
设置状态变量值后不要立即读取状态变量
const newValue = { newValue: 42 }
setChosenCard(newValue)
setMyCards(prevState => [...prevState, newValue])
使用useReducer
如果您的应用程序经常修改多个相互依赖的状态变量,那么最好使用
useReducer
而不是 useState
。它将允许您定义单个操作,如果调度该操作,则会同时更新应用程序状态中的chosenCard
和myCards
使用 useEffect 管理状态依赖关系
useEffect(
()=> chosenCard !== null && setMyCards(prevState => [...prevState, {...chosenCard}]),
[chosenCard]
)
这将确保仅在状态更改生效后才调用
setMyCards
。然而,不鼓励过度使用 useEffect,因为这会导致很难推断隐式状态更改:you-might-not-need-an-effect