React基础 第十四章(正确更新State中的对象)

在React中,正确地管理和更新state是保持应用性能和可维护性的关键。本文将详细介绍如何在React中更新state中的对象,包括不可变性的概念、如何处理嵌套对象更新,以及使用Immer库简化更新逻辑。

不可变性和state更新

React中的state应该被视为不可变的。这意味着你不应该直接修改state对象,而是应该创建一个新的对象并用它来更新state。

技巧:

  • 使用展开运算符...来复制对象并更新state。
  • 对于嵌套对象,从最深的层次开始,为每一层创建新的对象。

示例:

jsx 复制代码
const [position, setPosition] = useState({ x: 0, y: 0 });

function handlePointerMove(e) {
  // 创建新的对象来更新state
  setPosition({
    ...position,
    x: e.clientX,
    y: e.clientY
  });
}

注意事项:

  • 直接修改state中的对象不会触发组件重新渲染。
  • 使用展开语法时,记住它只能进行浅拷贝。

正确代码:

jsx 复制代码
setPosition({
  ...position,
  x: e.clientX
});

错误代码:

jsx 复制代码
position.x = e.clientX; // 错误:直接修改了state对象

更新嵌套对象

在React中更新嵌套对象时,你需要为对象的每一层创建一个新的副本。

技巧:

  • 使用展开语法为嵌套对象的每一层创建新的副本。
  • 为了避免深层次的展开,可以使用库如Immer来简化过程。

示例:

jsx 复制代码
const [person, setPerson] = useState({
  name: 'Niki de Saint Phalle',
  artwork: {
    title: 'Blue Nana',
    city: 'Hamburg',
    image: 'https://i.imgur.com/Sd1AgUOm.jpg'
  }
});

function handleCityChange(e) {
  setPerson({
    ...person,
    artwork: {
      ...person.artwork,
      city: e.target.value
    }
  });
}

注意事项:

  • 当更新嵌套对象时,确保你没有遗漏任何层次的复制。
  • 如果对象结构复杂,考虑使用Immer等库来简化更新逻辑。

正确代码:

jsx 复制代码
setPerson({
  ...person,
  artwork: {
    ...person.artwork,
    city: 'New Delhi'
  }
});

错误代码:

jsx 复制代码
person.artwork.city = 'New Delhi'; // 错误:直接修改了嵌套对象

使用Immer简化状态更新

Immer是一个帮助你以不可变的方式更新复杂state的库。它允许你编写看似直接修改state的代码,但实际上它会为你处理不可变更新。

技巧:

  • 使用Immer的produce函数来处理state更新。
  • 在produce的回调中,你可以直接修改draft对象,而Immer会为你生成新的不可变状态。

示例:

jsx 复制代码
import { useImmer } from 'use-immer';

const [person, updatePerson] = useImmer({
  name: 'Niki de Saint Phalle',
  artwork: {
    title: 'Blue Nana',
    city: 'Hamburg',
    image: 'https://i.imgur.com/Sd1AgUOm.jpg'
  }
});

function handleCityChange(e) {
  updatePerson(draft => {
    draft.artwork.city = e.target.value;
  });
}

注意事项:

  • Immer使用代理(Proxy)来追踪变化,所以确保你的环境支持Proxy。
  • 使用Immer时,你无需担心深层次的展开和复制。

记住,不可变性是React状态管理的核心原则之一,它能够帮助你避免许多潜在的问题,如性能下降和bug的产生。

相关推荐
treasure1405 小时前
【复古】浅尝Django前后端不分离
前端·css·python·django·bootstrap·html·web
jay神6 小时前
基于 YOLOv8 的手势识别系统(Web 版)
前端·人工智能·python·深度学习·yolo·计算机视觉·计算机毕业设计
屏什么录6 小时前
长时间录屏中途崩溃:MP4 打不开的 6 种救回方案与参数设置
前端·音视频开发
code_Bo6 小时前
不只命令行:我把跨 Agent 会话同步做成了桌面应用
前端·javascript·后端
kyriewen7 小时前
AI 能把页面写出来,为什么改个需求就开始崩?
前端·javascript·人工智能
涛涛ing8 小时前
2026年最值得关注的前端变化,藏在“默认值”里
前端
亿元程序员10 小时前
太牛了!这AI做出来的游戏,居然还能变现!
前端
hellice10 小时前
闪传 FlashDrop 实战:我用 300 行 Node 代码做了个「4 位取件码」临时文件中转站
前端·产品
用户08297732600510 小时前
RTX 5500 MIG 踩坑记录:切分之后模型跑不起来,排错整整一下午
前端
Lank_M10 小时前
AI 放大后的图更清楚,但它不能当原图入库
前端