Состояние компонента
Что делает setState
?
Метод setState()
планирует изменение объекта состояния (state
) компонента. Когда состояние меняется, компонент рендерится повторно.
Какая разница между state
и props
?
props
(намеренно сокращённо от англ. «properties» — свойства) и state
— это обычные JavaScript-объекты. Несмотря на то, что оба содержат информацию, которая влияет на то, что увидим после рендера, есть существенное различие: props
передаётся в компонент (служат как параметры функции), в то время как state
находится внутри компонента (по аналогии с переменными, которые объявлены внутри функции).
Несколько полезных ресурсов для дальнейшего изучения, в каких случаях использовать props
, а в каких — state
:
Почему setState
даёт неверное значение?
В React как this.props
, так и this.state
представляют значения, которые уже были отрендерены, например, то, что видите на экране.
Вызовы setState
являются асинхронными, поэтому не стоит рассчитывать, что this.state
отобразит новое значение мгновенно после вызова setState
. Необходимо добавить функцию, которая сработает только после обновления состояния, если нужно получить новое значение, основанное на текущем состоянии (ниже подробный пример).
Пример кода, который не будет работать так, как ожидаем:
incrementCount() {
// Примечание: это *не* сработает, как ожидалось.
this.setState({count: this.state.count + 1});
}
handleSomething() {
// Допустим, что `this.state.count` начинается с 0.
this.incrementCount();
this.incrementCount();
this.incrementCount();
// Когда React делает последующий рендер компонента, `this.state.count` будет 1, хотя мы ожидаем 3.
// Так происходит, потому что функция `incrementCount()` берёт своё значение из `this.state.count`,
// но React не обновляет `this.state.count`, пока компонент не отрендерится снова.
// Получается, что `incrementCount()` обращается к текущему значению `this.state.count`, а это 0 каждый раз, и добавляет 1.
// Как исправить это — разберём ниже!
}
Далее перейдём к исправлению указанной проблемы.
Как обновить состояние значениями, которые зависят от текущего состояния?
Нужно добавить функцию вместо объекта к setState
, которая будет срабатывать только на самой последней версии состояния (пример ниже).
В чём разница между добавлением объекта или функции к setState
?
Добавление функции даёт вам доступ к текущему состоянию внутри самой функции. Так как setState
вызовы «сгруппированы», это помогает связать изменения и гарантирует, что они будут выполняться друг за другом, а не конфликтовать.
incrementCount() {
this.setState((state) => {
// Важно: используем `state` вместо `this.state` при обновлении.
return {count: state.count + 1}
});
}
handleSomething() {
// Возьмём снова для примера, что `this.state.count` начинается с 0.
this.incrementCount();
this.incrementCount();
this.incrementCount();
// Если посмотреть на значение `this.state.count` сейчас, это будет по-прежнему 0.
// Но когда React отрендерит компонент снова, будет уже 3.
}
Когда setState
работает асинхронно?
В настоящее время setState
работает асинхронно внутри обработчиков событий.
Это даёт гарантию, например, когда Родитель
и Ребёнок
вызывают setState
во время клика, Ребёнок
не будет рендериться дважды. Вместо этого React «откладывает» обновление состояния в самый конец событий в браузере. Это помогает сильно повысить производительность больших приложений.
Но не стоит полностью полагаться на такое поведение. В будущих версиях React будет использовать отложенные обновления состояния по умолчанию не только в обработчиках событий.
Почему React не обновляет this.state
синхронно?
Как говорилось ранее, React намеренно «ждёт» пока все компоненты вызовут setState()
в своих обработчиках событий прежде чем начать повторный рендер. Это избавляет от ненужных повторных рендеров.
Вы можете задаваться вопросом: почему React не может просто сразу обновить this.state
без повторного рендеринга?
На это есть две причины:
- Это нарушит логику работы
props
иstate
, а значит станет причиной многих багов, которые будет сложно исправить. - Это сделало бы невозможным реализацию некоторых возможностей, над которыми мы сейчас работаем.
Этот GitHub-комментарий рассматривает конкретные примеры, которые помогут глубже изучить этот вопрос.
Стоит ли использовать такие библиотеки, как Redux или MobX?
Но вообще будет здорово сначала изучить React, прежде чем переходить к библиотекам. Можно создать готовое рабочее приложение, используя только React.