如果 props 没有改变,无状态组件会重新渲染吗?

IT技术 reactjs
2021-04-03 23:13:48

我学到的关于 React 的一件事是,如果组件的 props 没有改变,那么 React 不会费心重新渲染组件。对于无状态组件也是如此吗?或者它们的行为更像是“愚蠢”的函数并且每次都被执行?

例如,如果我有:

import StatelessComponent from '../StatelessComponent';

export default class DocumentsTable extends React.Component {
  state = {
    something: 'foobar',
  };

  render() {
    return (
      <div>
        { this.state.something }
        <StatelessComponent theOnlyProp='baz'>
      </div>
    )
  }
};

this.state.something更新其值时,是否<StatelessComponent>会重新渲染?或者它是否“聪明”到可以看到它的 props 没有改变,就像其他 React 组件一样?

3个回答

2018 年 10 月 25 日更新

从 React 16.6 开始,您可以将React.memo用于功能组件以防止重新渲染,类似于PureComponent类组件:

const MyComponent = React.memo((props) => {
  return (
    /* markup */
  );
});

此外,备忘录进行内部优化

与 userland memo() 高阶组件实现不同,React 内置的实现可以通过避免额外的组件层来提高效率。块引用


旧答案

是的,如果setState()在组件本身或其父组件之一中调用,它们总是重新渲染1(除非您使用 React.memo 如上所述),因为功能性无状态组件不携带shouldComponentUpdate事实上,每个 React 组件都会被重新渲染1,除非它们实现shouldComponentUpdate.


需要注意的是,调用 render() 并不意味着 DOM 节点正在以任何方式被操纵render方法只是服务于diff 算法来决定哪些 DOM 节点需要真正连接/分离。请注意,这 render() 并不昂贵,昂贵的是 DOM 操作只有在render()返回不同的虚拟树时才会执行它们

来自 React 的文档

需要明确的是,在此上下文中重新渲染意味着为所有组件调用渲染,这并不意味着 React 将卸载并重新安装它们。它只会按照前面部分所述的规则应用差异。

只是不要担心,render()除非您的组件很大,否则我们会调用let ,那么最好使用实现shouldComponentUpdate().

看看这里的一个有趣的讨论。

1表示render()调用的是组件的函数,而不是底层 DOM 节点正在被操作。

谢谢你提到.memo这正是我所需要的。
2021-05-31 23:13:48

请参阅 react 不仅会重新渲染,如果 props 发生更改,它甚至会在有任何状态更改时重新渲染自身。在您的情况下,组件将随着您的状态发生变化而重新呈现。react 的工作方式基于一种名为Reconciliation的算法,该算法的作用是将您的虚拟 DOM 与真实 DOM 进行比较,如果发现任何更改,则它会通过将其替换为您的虚拟 DOM 来重新呈现您的实际 DOM,因此状态的任何更改将导致整个组件的重新渲染。

如果无状态组件的 props 没有改变,它会重新渲染吗?

是的。即使没有任何变化,也将调用无状态渲染函数。然而,React 会在协调阶段将虚拟 DOM(由渲染函数生成)与现有 DOM 进行比较。这还远未完成,因此如果渲染函数的计算成本很高,则不理想。

一个纯组分确实有属性的默认浅层比较,并会停止渲染执行。Pure 组件视为一个普通的类 React 组件,它有一个shouldComponentUpdate与一个三元组进行比较,该三元组等于现有属性和新属性。

话虽如此,您可以使用 Recompose.pure ( https://github.com/acdlite/recompose/blob/master/docs/API.md#pure ) 将无状态组件包装纯组件它会自动执行,例如的纯组分,浅比较而不损害的短语法无国籍部件

import StatelessComponent from '../StatelessComponent';   
const PureChildFromStatelessComponent = Recompose.pure(StatelessComponent);
// ... 
<PureChildFromStatelessComponent ... />