Вы должны определить все свойства состояния компонента внутри конструктора?

Итак, я закончил читать эту статью, в которой в основном говорится о том, как v8 и другие движки javascript внутренне кэшируют "форму" объектов, так что, когда им нужно многократно обращаться к определенному свойству объекта, они могут просто использовать прямой адрес памяти вместо того, чтобы искать где в памяти этого объекта это конкретное свойство.

Это заставило меня задуматься: в 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 так что объект всегда согласован? Повлияет ли это на производительность каким-либо существенным образом?

4 ответа

Решение

TL;DR Выигрыш в производительности кажется незначительным, чтобы не стоить того.

Испытательная установка:

Я сделал 100000 детей этого класса:

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;

Дети сделаны следующим образом:

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 prop, чтобы либо вывести один и тот же HTML для каждого потомка, либо другой HTML.

Я также прошел в numKeys определить, сколько разных типов ключей должно быть на объекте. После тестирования display prop не сильно повлиял на время рендеринга DOM, поэтому я не сообщил об этом ниже. Все тесты были выполнены с yarn build && serve -s build с помощью create-react-app

Результаты

Один и тот же ключ для всех детей

Один и тот же ключ для всех детей

3 ключа для всех детей

3 ключа для всех детей

10 ключей для всех детей

10 ключей для всех детей

1000 ключей для всех детей

1000 ключей для всех детей* все тесты в Chrome 67.0.3396.99

Как видите, производительность для 100000 объектов незначительна, пока у вас не будет много объектов различной формы. Даже в этом случае ваше увеличение производительности составляет 700 мс на 100000 компонентов или 7 микросекунд на компонент. Это, конечно, не заявленное ускорение в 8 раз.

MOREOVER: Ваше время рендеринга, вероятно, будет уменьшено действиями DOM в чем-то реалистичном, а не синтетическом, как этот тест.

Помимо оптимизации, рекомендуется смоделировать все локальные поля состояния, даже если это просто data: null как вы упомянули. Таким образом, вы можете сбросить компонент обратно в исходное состояние с помощью простого вызова this.setState,

Для оптимизации и повышения производительности всегда рекомендуется инициализировать все переменные компонента в конструкторе, чтобы компонент загружался с начальными значениями и во время выполнения можно было избежать создания новых переменных состояния.

Основная причина для определения всех свойств заранее заключается в том, что он служит self documenting особенность вашего компонента.

Так

  1. это уменьшает необходимость добавлять комментарии
  2. это сокращает время, необходимое разработчику для ознакомления с компонентом

долгосрочный выигрыш времени / обслуживания при этом окупится, за исключением прироста производительности.

Другие вопросы по тегам