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