React useState 改变了我不变的初始状态

React useState changes my constant initial state

我的 selectItem 事件改变了我的 initialState,我故意将其保持不变。

Panel.js

import React, { useState } from "react";
import "./Panel.css";
import Item from "./Item";

const initialState = [
  { text: 1, isSelected: false },
  { text: 2, isSelected: false },
  { text: 3, isSelected: false },
  { text: 4, isSelected: false },
  { text: 5, isSelected: false }
];

export default function Panel() {
  const [items, setItems] = useState(initialState);

  const selectItem = k => {
    console.log(k);
    const updatedItems = [...initialState];
    updatedItems.find(item => item.text === k).isSelected = true;
    setItems(updatedItems);
  };

  return (
    <div className="Panel">
      {items.map(item => (
        <Item
          key={item.text}
          text={item.text}
          isSelected={item.isSelected}
          clicked={selectItem}
        />
      ))}
    </div>
  );
}

Item.js

import React from "react";
import "./Item.css";

export default function Item({ text, isSelected, clicked }) {
  return (
    <div className="Item" onClick={() => clicked(text)}>
      {isSelected ? <div style={{ backgroundColor: "red" }}>{text}</div> : text}
    </div>
  );
}

这样看,你的数组是一个对象数组,每个索引(项)都是对某个特定对象的引用。

基本上,当您创建 updatedItems 数组时,您会将其所有引用分散到一个新的“引用对象的数组”中。因此,从技术上讲,您使用的是完全相同的对象。一旦你 select 一个并改变它,你正在改变 initialStateitems 都引用的对象。

您正在做的是数组的浅克隆(副本)。

如果你想做一个深度克隆,一个简单的方法是:JSON.parse(JSON.stringify(initialState)).

您还可以使用 lodash/cloneDeep https://lodash.com/docs/4.17.15#cloneDeep

等实用程序

不过请记住,深度克隆也可能非常昂贵,而且并不总能得到想要的结果。

更改显示为 ...

的行

const updatedItems = [...initialState];

到...

const updatedItems = [...items];

initialState const 应该只用于初始化 items 状态值。

Sandbox ...