state和ref

在 React 中,state 的更新机制与 Vue 3 的 ref 确实存在本质区别:

Vue 3 的 ref 会对对象进行响应式代理,因此可以直接修改深层属性(如 obj.value.deep.prop = 123),Vue 能自动检测到变化并触发更新。

React 的 state 则遵循 "不可变性原则",不能直接修改深层属性,必须通过创建新对象的方式更新(表面上看是 "整体修改",实际是替换引用)。

具体对比示例

Vue 3 中可以直接修改深层属性:
复制代码
import { ref } from 'vue';

const user = ref({
  info: {
    name: '张三',
    age: 20
  }
});

// 直接修改深层属性,Vue 能检测到
user.value.info.age = 21; // 有效,视图会更新
React 中直接修改深层属性无效:
复制代码
import { useState } from 'react';

const [user, setUser] = useState({
  info: {
    name: '张三',
    age: 20
  }
});

// 错误做法:直接修改深层属性,React 无法检测
const wrongUpdate = () => {
  user.info.age = 21; // 无效,视图不会更新
  setUser(user); // 引用未变,React 认为状态没变化
};
React 正确的深层更新方式:

必须创建新对象(保持引用变化):

复制代码
const correctUpdate = () => {
  setUser({
    ...user, // 复制外层对象
    info: {
      ...user.info, // 复制内层对象
      age: 21 // 修改目标属性
    }
  });
};

核心原因

  • React 依赖引用变化检测状态更新(新旧状态引用不同才会触发重渲染)
  • Vue 3 基于Proxy 代理,能追踪对象内部属性的变化,不需要依赖引用变化

如果觉得手动处理深层对象麻烦,可以使用 immer 库简化操作,它允许用 "直接修改" 的写法,但内部会自动转换为不可变更新:

复制代码
import { produce } from 'immer';

const updateWithImmer = () => {
  setUser(produce(draft => {
    draft.info.age = 21; // 看似直接修改,实际是安全的
  }));
};

总结:React 中不能像 Vue 3 那样直接修改深层属性,必须通过创建新对象的方式更新,但可以借助工具库简化这个过程。

复制代码
import { useState } from 'react';

function UserProfile() {
  // 定义深层对象状态
  const [user, setUser] = useState({
    name: '张三',
    age: 25,
    address: {
      city: '北京',
      district: '朝阳区',
      street: '建国路88号'
    },
    hobbies: ['读书', '运动']
  });

  // 1. 修改浅层属性(一级属性)
  const updateName = () => {
    // 创建新对象,复制原有属性,只修改需要变更的部分
    setUser({
      ...user,  // 复制原有所有属性
      name: '张三丰'  // 覆盖需要修改的属性
    });
  };

  // 2. 修改深层属性(二级及以上)
  const updateCity = () => {
    setUser({
      ...user,  // 复制一级属性
      address: {
        ...user.address,  // 复制二级属性
        city: '上海'  // 覆盖需要修改的深层属性
      }
    });
  };

  // 3. 向深层数组添加元素
  const addHobby = () => {
    setUser({
      ...user,
      hobbies: [...user.hobbies, '编程']  // 复制原数组并添加新元素
    });
  };

  // 4. 复杂修改:同时修改多个层级的属性
  const complexUpdate = () => {
    setUser({
      ...user,
      age: 26,  // 修改一级属性
      address: {
        ...user.address,
        district: '浦东新区'  // 修改二级属性
      }
    });
  };

  return (
    <div>
      <h3>用户信息</h3>
      <p>姓名:{user.name}</p>
      <p>年龄:{user.age}</p>
      <p>城市:{user.address.city}</p>
      <p>区:{user.address.district}</p>
      <p>爱好:{user.hobbies.join(', ')}</p>

      <button onClick={updateName}>修改姓名</button>
      <button onClick={updateCity}>修改城市</button>
      <button onClick={addHobby}>添加爱好</button>
      <button onClick={complexUpdate}>复杂更新</button>
    </div>
  );
}

export default UserProfile;
相关推荐
正义的大古32 分钟前
OpenLayers地图交互 -- 章节十八:拖拽旋转和缩放交互详解
javascript·vue.js·openlayers
行者..................1 小时前
手动编译 OpenCV 4.1.0 源码,生成 ARM64 动态库 (.so),然后在 Petalinux 中打包使用。
前端·webpack·node.js
小爱同学_1 小时前
一次面试让我重新认识了 Cursor
前端·面试·程序员
golang学习记2 小时前
AI 乱写代码?不是模型不行,而是你的 VS Code 缺了 Context!MCP 才是破局关键
前端
星光不问赶路人2 小时前
Vite 中的 import.meta.glob vs 动态导入:该用哪个?
前端·vite
疯狂踩坑人2 小时前
【万字长文】让面试没有难撕的JS基础题
javascript·面试
z_y_j2299704382 小时前
服务器中使用Docker部署前端项目
服务器·前端·docker·容器
极客小俊2 小时前
【浅谈javascript禁术】 eval函数暗藏玄机?
javascript
迪丽热爱2 小时前
解决【npm : 无法加载文件 C:\Program Files\nodejs\npm.ps1,因为在此系统上禁止运行脚本。】问题
前端·npm·node.js
数字冰雹3 小时前
图观 流渲染场景服务器
服务器·前端·数据库·数据可视化