反应useState不触发重新渲染

时间:2019-05-23 00:21:51

标签: javascript reactjs react-hooks

我已经初始化了一个数组状态,当我更新它时,我的组件不会重新渲染。这是最小的概念验证:

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组件不会重新呈现。但是,如果我在5秒钟后执行的onChange函数中添加setTimeout,则表明数字确实已更新。

关于组件为什么不更新的任何想法?

这里是CodeSandbox,带有概念证明。

6 个答案:

答案 0 :(得分:4)

这里有两个问题。

首先,通过设置输入的值prop,可以防止其接收更改。尝试使用defaultValueDave correctly points out一样,管理输入值并不罕见。我只是说,按照问题中的实现,无论您尝试键入什么内容,输入都将在第一次更新后锁定为1的值。对此感到抱歉。

第二:您正在调用setNumbers并将其已拥有的数组传递给它。您已经更改了它的值之一,但是它仍然是相同的数组,我怀疑React并没有看到任何重新渲染的理由,因为状态没有改变。新数组是旧数组。

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

setNumbers([..old])

答案 1 :(得分:3)

您需要像这样numbers复制let old = [...numbers];

useState不会仅在更改值时更新值,因此如果它是44并变成7,它将更新。但是如何知道数组或对象是否已更改。这是通过引用进行的,因此当您进行let old = numbers时,您只是传递了一个引用而没有创建一个新的

答案 2 :(得分:2)

其他人已经给出了技术解决方案。对于为什么发生这种情况感到困惑的任何人,是因为setSomething()仅在且仅当先前状态和当前状态不同时才重新渲染组件。由于javascript中的数组是引用类型,因此,如果您在js中编辑数组的项,它仍然不会将引用更改为原始数组。在js看来,这两个数组是相同的,即使这些数组中的原始内容不同。这就是为什么setSomething()失败会检测到对旧数组所做的更改。

请注意,如果您使用类组件并使用setState()更新状态,则该组件将始终更新,而不管状态是否已更改。因此,您可以将功能组件更改为类组件作为解决方案。或遵循他人提供的答案。

答案 3 :(得分:1)

你可以像这样改变状态

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

或者如果你的 state 是 Array 你可以像这样改变

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

答案 4 :(得分:-1)

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

答案 5 :(得分:-3)

useState 是一个 React 钩子,它提供了在功能组件中拥有状态的功能。 通常它会在 useState 变量发生变化时通知 React 重新渲染组件。

{
      let old = numbers;
      old[0] = 1;
      setNumbers(old);
}

在上面的代码中,由于您引用的是同一个变量,它存储的是引用而不是值,因此 React 不知道最新的更改,因为引用与之前的相同。

为了克服使用下面的hack,它不会复制引用而是一个深层复制(复制值)

{
      let old = JSON.parse(JSON.stringify(numbers));
      old[0] = 1;
      setNumbers(old);
}

快乐编码:)

相关问题