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;
相关推荐
行走的陀螺仪10 小时前
uni-app + Vue3编辑页/新增页面给列表页传参
前端·vue.js·uni-app
摘星编程10 小时前
React Native + OpenHarmony:Spinner旋转加载器
javascript·react native·react.js
We་ct11 小时前
LeetCode 205. 同构字符串:解题思路+代码优化全解析
前端·算法·leetcode·typescript
2301_8127314111 小时前
CSS3笔记
前端·笔记·css3
ziblog11 小时前
CSS3白云飘动动画特效
前端·css·css3
越努力越幸运50811 小时前
CSS3学习之网格布局grid
前端·学习·css3
半斤鸡胗11 小时前
css3基础
前端·css
ziblog11 小时前
CSS3创意精美页面过渡动画效果
前端·css·css3
akangznl11 小时前
第四章 初识css3
前端·css·css3·html5
会豪11 小时前
深入理解 CSS3 滤镜(filter):从基础到实战进阶
前端·css·css3