State 可以保存任何类型的 JavaScript 值,包括对象。但是你不应该直接改变你在 React 状态下持有的对象。相反,当你想更新一个对象时,你需要创建一个新对象(或复制一个现有对象),然后设置状态以使用该副本。
const [position, setPosition] = useState({ x: 0, y: 0 });
从技术上讲,可以更改对象本身的内容。这称为突变:
position.x = 5;
然而,尽管 React 状态中的对象在技术上是可变的,但您应该将它们视为不可变的——就像数字、布尔值和字符串一样。您应该始终替换它们,而不是改变它们。
const [position, setPosition] = useState({ x: 0, y: 0 });
这样的代码是一个问题,因为它修改了状态中的现有对象:
position.x = e.clientX; position.y = e.clientY;
但是这样的代码绝对没问题,因为您正在改变刚刚创建的新对象:
const nextPosition = {}; nextPosition.x = e.clientX; nextPosition.y = e.clientY; setPosition(nextPosition);
事实上,它完全等同于这样写:
setPosition({ x: e.clientX, y: e.clientY });
只有当您更改已处于状态的现有对象时,变异才会成为问题。改变您刚刚创建的对象是可以的,因为还没有其他代码引用它。更改它不会意外影响依赖它的东西。这被称为“局部突变”。您甚至可以在渲染时进行局部突变。很方便,完全没问题!
我们常用的是使用传播语法复制对象,您可以使用... 对象传播语法,这样您就不需要单独复制每个属性。
setPerson({ ...person, // Copy the old fields firstName: e.target.value // But override this one });
用 Immer 编写简洁的更新逻辑
如果您的状态嵌套很深,您可能需要考虑将其展平。但是,如果您不想更改状态结构,您可能更喜欢嵌套传播的捷径。Immer是一个流行的库,它允许您使用方便但可变的语法进行编写,并负责为您生成副本。使用 Immer,您编写的代码看起来像是在“违反规则”并改变对象:
updatePerson(draft => { draft.artwork.city = 'Lagos'; });
但与常规突变不同的是,它不会覆盖过去的状态!
尝试 Immer:
运行npm install use-immer以将 Immer 添加为依赖项
然后替换 import { useState } from 'react'为import { useImmer } from 'use-immer'
例如:
import { useImmer } from 'use-immer'; export default function Form() { const [person, updatePerson] = useImmer({ name: 'Niki de Saint Phalle', artwork: { title: 'Blue Nana', city: 'Hamburg', image: 'https://i.imgur.com/Sd1AgUOm.jpg', } }); function handleNameChange(e) { updatePerson(draft => { draft.name = e.target.value; }); } function handleTitleChange(e) { updatePerson(draft => { draft.artwork.title = e.target.value; }); } function handleCityChange(e) { updatePerson(draft => { draft.artwork.city = e.target.value; }); } function handleImageChange(e) { updatePerson(draft => { draft.artwork.image = e.target.value; }); } return ( <> <label> Name: <input value={person.name} onChange={handleNameChange} /> </label> <label> Title: <input value={person.artwork.title} onChange={handleTitleChange} /> </label> <label> City: <input value={person.artwork.city} onChange={handleCityChange} /> </label> <label> Image: <input value={person.artwork.image} onChange={handleImageChange} /> </label> <p> <i>{person.artwork.title}</i> {' by '} {person.name} <br /> (located in {person.artwork.city}) </p> <img src={person.artwork.image} alt={person.artwork.title} /> </> ); }
请注意事件处理程序变得多么简洁。您可以根据需要在单个组件中混合搭配useState。useImmerImmer 是保持更新处理程序简洁的好方法,尤其是当您的状态中存在嵌套并且复制对象会导致重复代码时。
标签:updatePerson,target,状态,对象,更新,react,draft,artwork From: https://www.cnblogs.com/ximenchuifa/p/17356965.html