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

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

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

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


当前回答

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()更新状态,那么无论状态是否改变,组件总是会更新。因此,您可以将功能组件更改为类组件作为解决方案。或者按照别人提供的答案去做。

其他回答

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

你需要像这样复制数字let old =[…numbers];

useState只有在值发生变化时才会更新,所以如果它是44,变成7,它就会更新。但它如何知道数组或对象是否发生了变化。它是通过引用的,所以当你让old = numbers时,你只是传递了一个引用,而不是创建一个新的引用

引入组件的一个数组,该数组不是钩子的数组。例如:

const [numbers, setNumbers] = useState([0, 1, 2, 3]);

var numbersModify = []; //the value you want

最后:

setNumbers(numbersModify)

修改这个numbersModify,当钩子刷新时,它将返回0 numbersModify,钩子将保持这个状态。因此,看不到更改的问题将被消除。

:D

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

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

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

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

setNumbers([...old])