与基于 class 的方法相比,使用 Hooks 设置状态后重新渲染有何不同?

What are the differences when re-rendering after state was set with Hooks compared to the class-based approach?

Class 组件

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

Docs (setState API Reference):

setState() will always lead to a re-render unless shouldComponentUpdate() returns false.


Hooks(函数组件)

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

Docs (useState API Reference):

Bailing out of a state update

If you update a State Hook to the same value as the current state, React will bail out without rendering the children or firing effects. (React uses the Object.is comparison algorithm.)


密切相关的问题

  1. class 组件中的 this.setState 总是导致重新渲染是否正确,即使新的 state 值与之前的值相同?
  2. 函数组件 中使用钩子是否正确,useState 中的 setState 仅在 state 值时才导致重新渲染与之前的值不同?
  3. class组件render方法中用this.setState设置state,与设置state 带有钩子的函数组件的函数体内 ?
  4. 以下说法正确吗?
    • class组件中,如果我们在render方法中设置state,将会发生无限循环。这是因为 class 组件 并不关心新的 state 是否与之前的 state 相同。它只是在每个 this.setState.
    • 上不断重新渲染
    • 在带有钩子的 函数组件中 但是,在函数体内设置 state (它在重新渲染时运行类似于 render 方法class components) 会 not 是个问题,因为 function component 刚刚退出当它发现 state 与之前的 state.
    • 相同时重新渲染

Is it correct that this.setState in class components always cause a re-render, even when the new state value is identical to the previous?

如果您在 setState 中设置了一个有效值而不是返回 null,除非您的组件是 PureComponent 或者您实现了 shouldComponentUpdate

Is it correct that in function components with hooks, setState from useState only causes a re-render if the state value is different from the previous value?

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

Is setting state with this.setState inside the render method of a class component, the same as setting state inside the function body of a function component with hooks?

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

In a class component, if we set state in the render method an infinite loop will occur. This is because the class component does not care that the new state is the same as the previous state. It just keeps re-rendering on every this.setState.

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

In a function component with hooks however, setting state inside the function body (which runs at re-render similarly to the render method in class components) would not be an issue, because the function component just bails out of re-renders when it sees that the state is identical to the previous state.

不是 100% 正确,因为您可以使用以前的值触发状态更新,这样以前的值和当前值不是 same.For 示例

setCount(count => count + 1);

在这种情况下,你的组件仍然会陷入死循环

这不是对 OP 的直接回答,但对某些刚接触 React and/or Hooks 并在其副作用和渲染时间上苦苦挣扎的人来说可能有所帮助。

因为这里还没有提到:在功能组件中而不是使用前面提到的(参见已接受答案的评论)ShouldComponentUpdate() 函数,它仅适用于基于 class 的组件,您将使用 useEffect() 挂钩。有了它,您可以告诉您的组件何时 运行 副作用以及在什么条件下,例如当某些依赖项发生变化时。

在 React 文档的这个例子中,只有当 props.source 改变时,函数才会被执行。

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

React docs: useEffect()