我已经初始化了一个数组状态,当我更新它时,我的组件不会重新呈现。下面是一个最小的概念证明:

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秒后执行,它显示数字确实已经更新。

对于组件不更新的原因有什么想法吗?

这里是一个概念验证的代码和框。


当前回答

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

快乐编码:)

其他回答

你调用setNumbers并将它已经拥有的数组传递给它。你已经改变了它的一个值,但它仍然是相同的数组,我怀疑React没有看到任何理由重新渲染,因为状态没有改变;新数组就是旧数组。

避免这种情况的一个简单方法是将数组展开到一个新数组中:

setNumbers([...old])
  //define state using useState hook
  const [numbers, setNumbers] = React.useState([0, 1, 2, 3]);

  //copy existing numbers in temp
  let tempNumbers = [...numbers];
  // modify/add no
  tempNumbers.push(4);
  tempNumbers[0] = 10;
  // set modified numbers
  setNumbers(tempNumbers);

我对此没有任何骄傲,但它确实有效

anotherList = something
setSomething([])
setTimeout(()=>{ setSomething(anotherList)},0)

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

快乐编码:)

你可以像这样改变状态

const [state, setState] = ({})
setState({...state})

或者如果你的状态是Array,你可以这样改变

const [state, setState] = ([])
setState([...state])