首页 > 其他分享 >react 更新状态中的对象

react 更新状态中的对象

时间:2023-04-26 18:46:32浏览次数:39  
标签:updatePerson target 状态 对象 更新 react draft artwork

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

相关文章

  • 对象专用流Demon03
    packagetest2;importjava.io.*;//对象专用流publicclassDemo04{publicstaticvoidmain(String[]args){FileOutputStreamfos=null;ObjectOutputStreamoos=null;try{fos=newFileOutputStream("H:\\Java2234\\Te......
  • react18中antd的select选择器组件自定义下拉框的内容
    效果如图导入组件和图标import{Select}from'antd'import{ManOutlined,WomanOutlined}from'@ant-design/icons';const{Option}=Select;数据letuserListOption=[{value:1,label:"小明",avatar:"http://xxx......
  • python 函数是对象
    defhi(name="yasoob"):return"hi"+nameprint(hi())#output:'hiyasoob'#我们甚至可以将一个函数赋值给一个变量,比如greet=hi#我们这里没有在使用小括号,因为我们并不是在调用hi函数#而是在将它放在greet变量里头。我们尝试运行下这个print(greet())#out......
  • Java通过反射给final对象赋值(代码库)
    直接赋值会报错Methodthrew'java.lang.UnsupportedOperationException'exception.给没有set方法的类如下赋值publicstaticvoidsetFieldValue(Objectobj,StringfieldName,Objectval){if(isEmpty(obj)||isEmpty(fieldName))return;ClasssuperClas......
  • 第十四章:内置对象
    学习要点:1.Global对象2.Math对象ECMA-262对内置对象的定义是:“由ECMAScript实现提供的、不依赖宿主环境的对象,这些对象在ECMAScript程序执行之前就已经存在了。”意思就是说,开发人员不必显示地实例化内置对象;因为它们已经实例化了。ECMA-262只定义了两个内置对象:Global和......
  • 第十五章:面向对象与原型
    学习要点:1.学习条件2.创建对象3.原型4.继承ECMAScript有两种开发模式:1.函数式(过程化),2.面向对象(OOP)。面向对象的语言有一个标志,那就是类的概念,而通过类可以创建任意多个具有相同属性和方法的对象。但是,ECMAScript没有类的概念,因此它的对象也与基于类的语言中的对象有所不同。......
  • 【更新公告】AirtestIDE更新至1.2.15版本
    1.前言本次更新为AirtestIDE、Airtest、Poco、iOS-tagent更新。AirtestIDE更新至1.2.15版本,Airtest更新为1.2.10版本,Poco更新为1.0.89版本,iOS-tagent重新梳理了master分支内容。更新内容详见下文。2.更新内容1)AirtestIDE更新至1.2.15版本新版IDE主要是更新了内置python环境......
  • [转]前端传嵌套对象参数给spring mvc
    在使用springmvc开发web应用时,感觉springmvc的controller方法能自动将参数注入到方法的参数对象中,极大的方便了开发。但是,在遇到有嵌套对象的时候,比如订单对象有个属性是用户对象,就不好处理了。一种情况是,传递的参数都是作为post方法的请求体,我们可以用RequestBody注解。但是当条......
  • 数据科学 IPython 笔记本 7.4 Pandas 对象介绍
    7.4Pandas对象介绍原文:IntroducingPandasObjects译者:飞龙协议:CCBY-NC-SA4.0本节是《Python数据科学手册》(PythonDataScienceHandbook)的摘录。在最基本的层面上,Pandas对象可以认为是NumPy结构化数组的增强版本,其中行和列用标签而不是简单的整数索引来标识。我们将在本......
  • react点击滑块验证
     css.wrap-num{width:300px;}@keyframesdefaultWave{0%{transform:scale(1);}20%{transform:scale(1.23);}40%{transform:scale(1);}100%{transform:scale(1);}}//旋转@keyframesloadingWave{0%{......