与基于类的方法相比,在使用 Hooks 设置状态后重新渲染有什么区别?

IT技术 javascript reactjs react-hooks
2021-04-07 17:59:59

类组件

在 React 类组件中,我们被告知setState 总是会导致重新渲染,无论状态是否实际更改为新值。实际上,当状态更新为之前相同的,组件重新渲染

文档(setState API 参考)

setState() 将始终导致重新渲染,除非 shouldComponentUpdate() 返回 false。


钩子(函数组件)

但是,使用钩子,文档指定将状态更新为与先前状态相同的值,不会导致(子组件)重新渲染:

文档(useState API 参考)

退出状态更新

如果您将 State Hook 更新为与当前状态相同的值,React 将退出而不渲染子项或触发效果。(React 使用 Object.is 比较算法。)


密切相关的问题

  1. this.setState即使新state值与以前的值相同,类中的组件总是会导致重新渲染,这是否正确
  2. 它是正确的,在功能部件与钩,setStateuseState只能导致重新绘制,如果state值与前值不同?
  3. 类组件方法内部设置statewith 和this.setState函数组件的函数体内部设置带钩子一样吗?renderstate
  4. 以下是否正确?
    • 类组件中,如果我们staterender方法中设置就会发生无限循环。这是因为class 组件并不关心 newstate是否与之前的相同state它只是在每个this.setState.
    • 然而,带有钩子函数组件中,state函数体内的设置render类组件中方法类似地在重新渲染时运行不会成为问题,因为函数组件只是在看到state与前一个相同state
2个回答

类组件中的 this.setState 总是导致重新渲染是否正确,即使新状态值与之前的值相同?

如果在 setState 中设置除返回 null 之外的有效值,除非您的组件是 PureComponent 或您实现了 shouldComponentUpdate,否则重新渲染将始终由类组件中的 react 触发

在带有钩子的函数组件中,如果状态值与之前的值不同,useState 中的 setState 只会导致重新渲染,这是否正确?

对于使用useState钩子的功能组件,如果以相同的状态调用 setter,则不会触发重新渲染。但是对于偶尔的情况,如果立即调用 setter,它确实会导致两个渲染而不是一个渲染

在类组件的render 方法中使用this.setState 设置状态,是否与使用钩子在函数组件的函数体中设置状态相同?

技术上是的,直接在渲染方法中设置状态将导致函数在类组件导致无限循环的情况下触发重新渲染,如果状态值不同,则功能组件就是这种情况。无论如何,它仍然会导致问题,因为由于功能组件直接调用状态更新,任何其他状态更新都将被恢复

在类组件中,如果我们在 render 方法中设置状态,将会发生无限循环。这是因为类组件并不关心新状态是否与之前的状态相同。它只是在每个 this.setState 上不断重新渲染。

是的,因此建议不要在渲染中直接调用 setState

然而,在带有钩子的函数组件中,在函数体内设置状态(它在重新渲染时运行,类似于类组件中的渲染方法)不会成为问题,因为函数组件只是在看到时退出重新渲染状态与之前的状态相同。

不是 100% 正确,因为您可以使用先前值触发状态更新,从而使先前值和当前值不同。例如

setCount(count => count + 1);

在这种情况下,您的组件仍将陷入无限循环

@Magnus,是的,我的错别字。更新了答案
2021-05-23 17:59:59
随着时间的推移,我已经以一种或另一种方式测试了上述场景
2021-06-01 17:59:59
@Magnus,是的,你是对的。效果是功能组件的附加逻辑,在类组件的渲染中不存在
2021-06-05 17:59:59
谢谢,深表感谢。你在哪里可以找到所有这些信息?官方文档几乎没有关于何时以及为什么会发生重新渲染的信息。他们真的应该创建一个关于该主题的页面......
2021-06-14 17:59:59
如果你实现 shouldComponentUpdate 以在 state 或 props 没有改变的情况下返回 false,那么你的组件将不会重新渲染
2021-06-15 17:59:59

这不是对 OP 的直接回答,而是与某些 React 和/或 Hooks 新手并在其副作用和渲染时间方面苦苦挣扎的人相关,并且可能会有所帮助。

由于此处尚未提及:在功能组件中,而不是使用之前提到的(参见已接受答案的评论)ShouldComponentUpdate()函数,该函数仅适用于基于类的组件,您将使用useEffect()钩子。有了它,您可以告诉您的组件何时运行副作用以及在何种条件下运行,例如当某些依赖项发生变化时。

在 React 文档中的这个示例中,只有在props.source更改时,才会执行该函数。

useEffect(
  () => {
    const subscription = props.source.subscribe();
    return () => {
      subscription.unsubscribe();
    };
  },
  [props.source],
);

react文档:useEffect()