You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React中子组件onClick事件触发两个父组件状态更新函数仅执行一个的问题排查

问题分析与解决方案

嘿,我帮你捋捋这个问题的根源,以及怎么解决它~

你遇到的核心问题是React的setState是异步操作,而且你在更新状态时依赖的是当前渲染周期里的user快照,导致两次连续的更新互相覆盖了。

为什么会出现这个情况?

当你在子组件的点击事件里连续调用props.isBeginner(true)和props.nextStep(2)时,这两个函数里的setUser({...user, ...})都是基于调用瞬间的user状态来生成新对象的。因为setState不会立即更新state,第一个更新还没完成,第二个更新就已经用了旧的user值,所以最后只有一次更新会生效,另一次的修改被覆盖掉了。

解决方案

这里有两种靠谱的解决方式,你可以根据自己的习惯选:

方案1:使用函数式更新(推荐)

把父组件里的两个更新函数改成基于前一个最新状态来更新,而不是依赖当前的user快照:

// 父组件函数修改为
isBeginner(b) {
  setUser(prevUser => ({ ...prevUser, first_timer: b }))
}

nextStep = (step) => {
  setUser(prevUser => ({ ...prevUser, setup_step: step }))
}

这种写法会让React每次都用最新的state来生成新状态,两次更新就不会互相覆盖了。

方案2:合并成一次state更新

既然两个函数都是更新同一个user对象的不同属性,不如直接合并成一个函数,一次完成所有修改:

// 父组件新增一个合并更新的函数
updateUser = (updates) => {
  setUser(prevUser => ({ ...prevUser, ...updates }))
}

然后在子组件里这样调用:

<button 
  id='but2' 
  onClick={() => props.updateUser({ first_timer: true, setup_step: 2 })} 
  className={classes.chooseButton}
>
  Choice number 1
</button>

这样只需要一次setState操作,既高效又不会有冲突。

额外的小bug修复

顺便提一下,你的中间组件的default分支没有写return,这会导致默认情况无法渲染组件,记得补上:

default: { return <StepOne isBeginner={props.isBeginner} nextStep={ props.nextStep}/> }

内容的提问来源于stack exchange,提问作者Marc Abdel Wahed

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.28 15:27:36