React 数组状态在功能组件更新时不断重置

React array state keeps resetting on update in functional component

我创建了一个 React 组件,其数组状态 state.colors 包含三个十六进制值(初始状态为 ['#aaaaaa', '#aaaaaa', '#aaaaaa'])。 state.colors 数组中的每个值都可以使用颜色选择器进行更新。作为测试,我将第一种颜色更新为红色,将第二种颜色更新为绿色,将第三种颜色更新为蓝色。这在 class 组件中按预期工作(如下面的屏幕截图所示)。


class EditArtworkClass extends React.Component {
  constructor(props) {
    this.state = {
      colors: initialPalette
    };
  }

  setColor(index, hex) {
    const clonedColors = _.clone(this.state.colors);
    clonedColors[index] = hex;

    this.setState(
      {
        colors: clonedColors
      },
      () => {
        console.log("updated");
      }
    );
  }

  // other code here
}

Class 组件 - 在选择颜色之前:

Class 组件 - 选择颜色后(state.colors 具有正确的十六进制值):

但是,我在使用功能组件时遇到了问题。每次我使用颜色选择器更新颜色时,colors 状态数组中的所有其他值都会重置为初始值 (#aaaaaa)。如果我将第一种颜色设置为红色,第二种颜色为蓝色,第三种颜色为绿色,只有 colors 数组中的最后一个值将具有正确的十六进制,因为其他两个值在更新时被重置为 #aaaaaa第三种颜色。

export default function EditArtworkFunctional() {
  const [colors, setColors] = useState(initialPalette);

  const setColor = (index, hex) => {
    const clonedColors = _.clone(colors);
    clonedColors[index] = hex;

    return clonedColors;
  };

  // Other code here
}

功能组件 - 选择颜色之前:

功能组件-选择颜色后(只有我选择的最后一种颜色在状态下具有正确的十六进制):

请注意,颜色选择器是不受控制的组件,它将显示您选择的颜色,而不是 colors 状态数组中的颜色。

我在下面的 Codesandbox Link 中创建了一个可复制的迷你应用程序。

Condesandbox Link: https://codesandbox.io/s/class-vs-functional-component-array-state-8lnzd

对于为什么会发生这种情况,我的想法为零,因此将不胜感激任何帮助或指导。

更新:我已经使用@TalOrlanczyk 的回答解决了这个问题。诀窍是在更新时使用可选参数检索以前的状态。您可以查看 CodeSandbox repo of the working version here.

这是因为两个原因

  1. const clonedColors = _.clone(colors) 使用这个深克隆数组不是我们想要的,我们必须对数组进行浅拷贝。因此,const clonedColors = colors 将是正确的方法。
  2. setColors(clonedColors) 不能正常工作,但如果我们 setState 使用扩展语法 setColors([...clonedColors]) 它会。这是因为数组只是一个引用,如果状态没有获得新的引用,React setState 将不会重新渲染。这就是我们使用扩展语法 [...clonedColors] 发送新数组引用的原因。感谢@TalOrlanczyk 的原因。
const setColor = (index, color) => {
    const clonedColors = colors;
    clonedColors[index] = color;
    setColors([...clonedColors]);
    console.log(colors);
};

这是Updated Codesandbox Link

我想我解决了问题

const setColor = (index, hex) => {
    setColors((prev) => {
      console.log(prev);
      const clonedColors = [...prev];
      clonedColors[index] = hex;
      return clonedColors;
    });
  };

就像@theWellHopeErr 说的那样是因为它发生是因为你没有将它作为传播运算符发送 这是发生的,因为数组是引用,如果您更改相同的引用,它可能会更改值,但使用状态不会捕获它,因为它不是新引用。

你应该知道的另一件事是使用这样的(与上一个)要好得多,因为那样你可以确保你得到你插入这个状态的最后一个真实输入

更新

扩展运算符仅适用于浅表,只有当它是深表时才适用,例如带有 属性 的对象,这将不起作用,并且还会更改原始状态。

不要改变当前状态,这是 React 中的反模式 这是一个完美解释它的帖子

克隆数组 要进行深度克隆,您应该使用

a good artical in medium that explain about shallow and deep clone