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

React严格模式下类方法更新状态触发两次的原因咨询

问题分析:React严格模式下类方法更新状态触发两次的原因

你的写法确实存在副作用问题,这正是React严格模式要排查的点。严格模式会刻意调用两次状态更新函数(包括useState的更新器回调),目的是暴露隐藏的副作用——而你的示例1正好触发了这个问题,示例2则没有。

核心差异:是否修改了原状态实例

  • 示例1的问题:
    你的ItemModel类的increaseQuantity()方法直接修改了实例本身的quantity属性:

    increaseQuantity = () => {
      this.quantity = this.quantity + 1 // 直接修改原实例的属性
      return this
    }
    

    在状态更新函数里调用item.increaseQuantity()时,已经修改了原状态中保存的ItemModel实例。严格模式下,这个更新函数会被执行两次:

    1. 第一次调用:原实例的quantity从1变成2,然后基于这个实例创建新对象
    2. 第二次调用:原实例的quantity已经是2了,再调用一次变成3,最后创建的新对象quantity就是3
      所以最终你看到的是每次点击数量+2。

    虽然你最后用{...item}创建了新对象,但调用方法的步骤已经先修改了原状态里的实例,这属于在纯函数(状态更新函数应该是纯函数)里产生了副作用。

  • 示例2为什么正常:
    示例2里直接基于原item的quantity计算新值,没有修改原item的任何属性:

    { ...item, quantity: item.quantity + 1 }
    

    即使严格模式下更新函数被调用两次,每次计算都是基于原状态的quantity值(比如原是1,两次计算都是1+1=2),所以最终结果是正确的+1。整个过程没有修改原状态的对象,是纯函数操作。

修复方案

要让示例1在严格模式下正常工作,需要保证increaseQuantity()不修改原实例,而是返回一个新的ItemModel实例:

class ItemModel {
  id: number
  quantity: number
  name: string

  constructor(name: string, quantity = 1, id = Math.random()) {
    this.id = id
    this.quantity = quantity
    this.name = name
  }

  // 改为返回新实例,不修改原对象
  increaseQuantity = () => {
    return new ItemModel(this.name, this.quantity + 1, this.id)
  }

  decreaseQuantity = () => {
    const newQuantity = this.quantity >= 2 ? this.quantity - 1 : 1
    return new ItemModel(this.name, newQuantity, this.id)
  }
}

这样调用item.increaseQuantity()时不会修改原状态中的实例,状态更新函数变成纯函数,即使严格模式下执行两次,每次都是基于原实例创建新对象,最终结果只会+1。

内容的提问来源于stack exchange,提问作者user3146945

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 11:06:17