Skip to content

react 中 state 的更新

对象更新时避免 mutation

改变对象或者数组自身内容时, 就制造了一个 mutation

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

position.x = 5; // React state 中存放的对象视为不可变的, 应该替换它的值而不是修改

setPosition({ ...position, x: 5 }); // right

对于嵌套数组,需要多层使用 ...对象展开语法

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

// error
person.artwork.city = "New Delhi";

// right
setPerson({
  ...person, // 复制其它字段的数据
  artwork: {
    // 替换 artwork 字段
    ...person.artwork, // 复制之前 person.artwork 中的数据
    city: "New Delhi", // 但是将 city 的值替换为 New Delhi!
  },
});

数组更新时避免 mutation

避免使用:

  • 增加元素 push, unshift
  • 删除元素 pop, shift, splice
  • 替换元素 splice, arr[i] = ...
  • 排序 reverse, sort

这些方法会在原数组上进行修改

替换为:

  • 增加元素 concat, [...arr, element]
  • 删除元素 filter, slice
  • 替换元素 map
  • 排序 先复制一份数组

react 中大多数情况下会使用 slice 来进行增,删,改

例子:

jsx
import { useState } from "react";

const [users, setUsers] = useState(["Bob", "John"]);

// add
setUsers([...users, "snowinlu"]);
setUsers([...users, "lixiuxian"]);

// delete
setUsers(users.filter((u) => u === "Bob"));
setUsers(users.slice(1));

// change
const newArr = [...users];
newArr.reverse();
setUsers(newArr);

注意点: 即使你拷贝了数组,你还是不能直接修改其内部的元素

使用 Immer 库

Immer 库在 update 函数中提供 stateproxy 对象, 你可以直接直接在它上面进行修改

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",
  },
});

// right
updatePerson((draft) => {
  draft.artwork.city = "Lagos";
});
2025( )
今日 8.33%
本周 42.86%
本月 48.39%
本年 4.11%
Powered by Snowinlu | Copyright © 2024- | MIT License