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

时间:2017-10-13 19:41:40

标签: reactjs

我学到的关于React的一件事是,如果组件的道具没有改变,那么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>会重新呈现吗?或者它是否“聪明”足以看到它的道具没有像其他React组件那样改变?

3 个答案:

答案 0 :(得分:51)

更新25.10.2018

自React 16.6起,您可以使用React.memo来阻止重新渲染功能组件,类似于PureComponent类组件:

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

另外,备忘录会internal optimization

  

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

OLD ANSWER

是的,他们总是重新渲染 1 (除非您按照上面的说明使用React.memo)如果在组件本身中调用setState()或者它的父母,因为功能无状态的组件不带shouldComponentUpdate。实际上,除非实现shouldComponentUpdate,否则每个React组件都将被重新呈现 1

需要注意的是,调用 render() 并不代表DOM节点以任何方式被操纵render方法只是为diff algorithm提供服务来决定哪些DOM节点需要真正附加/分离。 请注意 render() 并不昂贵,而且昂贵的DOM操作。仅当render()返回不同的虚拟树时才会执行它们。

来自React的documentation

  

为了清楚起见,在此上下文中重新注册意味着为所有组件调用render,这并不意味着React将卸载并重新安装它们。它只会按照前面章节中规定的规则应用差异。

除非你的组件很庞大,否则不要担心并让render()被调用,那么你最好使用实现shouldComponentUpdate()的有状态组件。

here进行有趣的讨论。

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

答案 1 :(得分:1)

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

答案 2 :(得分:1)

  

如果无状态组件的道具未更改,是否会重新渲染?

是的。即使没有任何更改,也会调用无状态渲染功能。但是,React将在对帐阶段将虚拟DOM(由渲染函数生成)与现有DOM进行比较。这还远远不够,因此如果渲染函数的计算成本很高,则不是理想的选择。

纯组件确实具有该属性的默认浅表比较,因此将停止执行渲染。将纯组件视为普通的类React组件,该组件具有 shouldComponentUpdate ,与现有属性和新属性的三元组进行比较。 / p>

话虽如此,您可以使用Recompose.pure(https://github.com/acdlite/recompose/blob/master/docs/API.md#pure)将无状态组件包装为纯组件,就像纯组件,不影响无状态组件的简短语法的浅浅比较。

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