您应该在构造函数中定义组件状态的所有属性吗?

Should you define all properties of a component's state inside the constructor?

所以我读完了 this article,它基本上讨论了 v8 和其他 javascript 引擎如何在内部缓存对象的 "shape",以便当它们需要重复访问特定的 属性 在对象上,他们可以只使用直接内存地址,而不是查找特定 属性 在该对象内存中的位置。

这让我想到,在 React 中,您经常在构造函数中声明组件的状态,但不包括最终将包含在状态中的所有属性,例如:

class MyComponent extends React.Component {
   constructor(props) {
       super(props);
       this.state = {
          hasLoaded: false
       };
   }

   componentDidMount() {
       someAjaxRequest.then((response) => {
           this.setState({
              content: response.body,
              hasLoaded: true
           });
       });
   }

   render() {
       return this.state.hasLoaded ?
          <div>{this.state.content}</div> :
          <div>Loading...</div>;
   }
}

由于根据文章,状态对象不会保持一致的结构,这样做是否比在构造函数中定义所有可能的状态字段效率低?您是否应该始终至少添加所有属性,甚至为它们提供 null 的值,以便对象始终保持一致? 它会以任何实质性方式影响性能吗?

撇开优化不谈,对所有局部状态字段进行建模是一个好主意,即使它只是 data: null 正如您提到的那样。这样,您可以通过简单地调用 this.setState.

将组件重置回其初始状态

TL;DR 性能提升似乎微不足道,不值得。

测试设置:

我赚了 100,000 children class:

import React, { Component } from 'react';

const getRand = (min, max) => Math.floor(Math.random() * (max - min + 1)) + min;

class Child extends Component {
  constructor() {
    super();
    this.state = {
      loading: false,
    };
  }

  componentDidMount() {
    const key = getRand(1, this.props.numKeys);
    this.setState({
      key,
      [key]: 'bar',
    });
  }

  render() {
    if (this.props.display) {
      return <div>child {this.state.key} {this.state[this.state.key]}</div>
    }
    return <div>child 0</div>
  }
}

export default Child;

child仁制作如下:

const children = [];
for (let i = 0; i < 1 * 100 * 1000; i++) {
  children.push(<Child display={true} numKeys={1000} key={i} />);
}
return (
  <div>
    {children}
  </div>
);

我的想法是:我可以传入 display 属性来为每个 child 呈现相同的 HTML,或者呈现不同的 HTML.

我还传入了一个numKeys来确定object上应该有多少种不同类型的键。经过测试,display 属性并没有显着影响 DOM 渲染时间,所以我没有在下面报告。所有测试都是 运行 和 yarn build && serve -s build 通过 create-react-app

结果

所有 children

都使用相同的密钥

所有 children

3 个键

所有 children

10 个键

所有 children

1000 个密钥

*Chrome 67.0.3396.99

中的所有测试

如您所见,100,000 objects 的性能可以忽略不计,除非您有很多不同形状的 objects。即便如此,您的性能提升还是超过 100,000 个组件 700 毫秒,或每个组件 7 微秒。这肯定不是声称的 8 倍加速。

此外:您的渲染时间可能会因 DOM 任何现实的动作而变得相形见绌,而不是像这个测试那样合成。

为了优化和更好的性能,始终建议在构造函数中初始化所有组件变量,以便组件加载初始值并避免在 运行 时创建新的状态变量。

预先定义所有属性的主要原因是它用作组件的 self documenting 功能。

所以

  1. 它减少了添加评论的需要
  2. 它减少了开发人员熟悉 him/herself 组件所需的时间

这样做的长期 time/maintenance 收益将收回成本,性能收益除外。