Вы должны определить все свойства состояния компонента внутри конструктора?
Итак, я закончил читать эту статью, в которой в основном говорится о том, как 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 ключа для всех детей
10 ключей для всех детей
1000 ключей для всех детей
* все тесты в Chrome 67.0.3396.99
Как видите, производительность для 100000 объектов незначительна, пока у вас не будет много объектов различной формы. Даже в этом случае ваше увеличение производительности составляет 700 мс на 100000 компонентов или 7 микросекунд на компонент. Это, конечно, не заявленное ускорение в 8 раз.
MOREOVER: Ваше время рендеринга, вероятно, будет уменьшено действиями DOM в чем-то реалистичном, а не синтетическом, как этот тест.
Помимо оптимизации, рекомендуется смоделировать все локальные поля состояния, даже если это просто data: null
как вы упомянули. Таким образом, вы можете сбросить компонент обратно в исходное состояние с помощью простого вызова this.setState
,
Для оптимизации и повышения производительности всегда рекомендуется инициализировать все переменные компонента в конструкторе, чтобы компонент загружался с начальными значениями и во время выполнения можно было избежать создания новых переменных состояния.
Основная причина для определения всех свойств заранее заключается в том, что он служит self documenting
особенность вашего компонента.
Так
- это уменьшает необходимость добавлять комментарии
- это сокращает время, необходимое разработчику для ознакомления с компонентом
долгосрочный выигрыш времени / обслуживания при этом окупится, за исключением прироста производительности.