我已经初始化了一个数组状态,当我更新它时,我的组件不会重新呈现。下面是一个最小的概念证明:
function App() {
const [numbers, setNumbers] = React.useState([0, 1, 2, 3]);
console.log("rendering...");
return (
<div className="App">
{numbers.map(number => (
<p>{number}</p>
))}
<input
type="text"
value={numbers[0].toString()}
onChange={newText => {
let old = numbers;
old[0] = 1;
setNumbers(old);
}}
/>
</div>
);
}
根据这段代码,似乎输入应该包含数字0来开始,并且任何时候它被改变,状态也应该改变。在输入中输入“02”后,App组件不会重新渲染。然而,如果我在onChange函数中添加了一个setTimeout,它在5秒后执行,它显示数字确实已经更新。
对于组件不更新的原因有什么想法吗?
这里是一个概念验证的代码和框。
我正在处理一个数组,其中有对象,我尝试了上面的几个。
我的财产是:
const [options, setOptions] = useState([
{ sno: "1", text: "" },
{ sno: "2", text: "" },
{ sno: "3", text: "" },
{ sno: "4", text: "" },
]);
现在我想在点击按钮时添加更多空白字段的选项,我会使用以下方式来实现我的目的:
<button
onClick={() => {
setOptions([...options, { sno: newArray.length + 1, text: "" }]);
}}
>
这解决了我的问题,我能够重新渲染组件,并添加一个对象到数组。
useState是一个React钩子,它提供了在函数组件中拥有State的功能。
通常,当useState变量发生变化时,它会通知React重新呈现组件。
{
let old = numbers;
old[0] = 1;
setNumbers(old);
}
在上面的代码中,由于你引用的是同一个变量,它存储的是引用而不是值,因此React不知道最新的变化,因为引用与之前的相同。
为了克服使用下面的hack,它不会复制引用,而是一个深度复制(复制值)
{
let old = JSON.parse(JSON.stringify(numbers));
old[0] = 1;
setNumbers(old);
}
快乐编码:)
Others have already given the technical solution. To anyone confused as to why this happens, is because setSomething() only re renders the component if and only if the previous and current state is different. Since arrays in javascript are reference types, if you edit an item of an array in js, it still doesn't change the reference to the original array. In js's eyes, these two arrays are the same, even though the original content inside those arrays are different. That's why setSomething() fails do detect the changes made to the old array.
注意,如果使用类组件并使用setState()更新状态,那么无论状态是否改变,组件总是会更新。因此,您可以将功能组件更改为类组件作为解决方案。或者按照别人提供的答案去做。