React钩子useState当值相等时仍会重新渲染一次setValue。

15

我有下面的示例代码:

function App() {
  console.log("render");
  const [val, setVal] = React.useState(0);
  return (
    <div className="App">
      <h1>{val}</h1>
      <button onClick={() => setVal(12)}>Update with same value</button>
    </div>
  );
}

当我点击一个按钮多次时,控制台会记录3次“render”消息。 对我来说,它应该只有2次:

  • 第一次渲染是1

  • 从val 0更新到12(点击按钮时)的更新为2

自此以后,由于相同的值(12)已更新为val,因此不应再重新呈现。

但为什么它会出现3次?这意味着尽管相同的值已经更新,但仍会重新呈现一次。

请知道的人解释一下,谢谢!

P / S:我已经发现只有在更改值然后将其更新为相同时才会导致额外的重新呈现。

function App() {
  console.log("render");
  const [val, setVal] = useState(4);
  return (
    <div className="App">
      <h1>{val}</h1>
      <button onClick={() => {
        setVal(val => val + 1)
      }}>Update</button>
      <button onClick={() => {
        setVal(val => val)
      }}>Update with same value</button>
    </div>
  );
}

第一次点击第二个按钮时,不会重新渲染,但如果先点击第一个按钮再点击第二个按钮,则第二个按钮会导致多一次重新渲染。

当第一次单击第二个按钮时,组件不会重新呈现。但是,如果您先单击第一个按钮再单击第二个按钮,则第二个按钮将导致额外的重新呈现。

2个回答

12
此线程可能会帮助您:React:设置状态时重新渲染 - Hooks vs. this.setState 此外,您可以查看这里的第二段,其中提到:

请注意,React 可能仍需要在放弃之前重新呈现该特定组件。这并不应成为问题,因为 React 不会不必要地“深入”树中。如果您在渲染时进行昂贵的计算,则可以使用 useMemo 进行优化。


11

React无法猜测render()的输出是否会改变:它必须再次调用render()并将结果与上一次的渲染结果进行比较。

随后魔法发生了:如果没有任何差异,则不会更新DOM;如果有差异,则尝试仅按需创建/销毁元素,因为这是昂贵的部分,而运行render()则不应该是。

更改状态通常会触发对render()的调用(但不一定会导致DOM修改),但如果您想控制此行为,请定义shouldComponentUpdate


注意:这适用于非hook组件。然而,我不知道hooks的行为与常规组件略有不同:似乎您在预期setState在值未更改时不会触发渲染方面是正确的——请参见Yash Joshi的答案。


我们也可以在类组件中使用 PureComponent,而不是手动定义 shouldComponentUpdate。但是当数据嵌套深度较大时,最好使用 shouldComponentUpdate - Yash Joshi
1
是的,但我仍然不知道为什么当值没有改变时,React为什么需要再次调用渲染函数。 - Quoc Van Tang
在非 hook 的情况下,React 选择比较旧/新的 render() 输出而不是旧/新的状态。在您的情况下(hook),文档仅表示如果值未更改,则保证跳过子元素的渲染。至于为什么仍然需要重新渲染 hook,我没有解释... - hugo
4
如有兴趣了解额外重新渲染背后的原因,请查看此评论链接:https://github.com/facebook/react/issues/14810#issuecomment-462089702 - Yash Joshi
我已经阅读了这条评论,并且发现只有在值更改后再次使用相同的值进行更新时才会导致额外的重新呈现(我编辑了我的帖子)。但老实说,我仍然不知道为什么它需要调用渲染1次。 :( - Quoc Van Tang

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接