Подробнее о state
В этом разделе мы посмотрим как изменение state влияет на компонент и немного "зацепим" stateless архитектуру.
Изменение state вызывает render компонента
Все указано в подзаголовке, предлагаю нам в этом убедиться:
Фрагмент компонента <Article />
:
Очистите консоль, и нажмите подробнее на любой из новостей:
Убедились? Несколько правил:
нельзя вызывать setState внутри render: "реакт бдит", и если изменилось состояние - начинает перерисовывать компонент - видит что изменилось состояние - начинает перерисовывать компонент...
render - дорогостоящая операция, поэтому внимательно относитесь к тому, где вы вызываете setState, и что это за собой влечет. Банальные
console.log
могут вам в этом помочь.
Очевидно, что если перерисовывается родительский компонент, то будут перерисованы и все дочерние компоненты.
В дальнейшем мы изучим разные "стадии жизни" компонента, и убедимся, что во время его "перерисовки" могут выполняться разные дорогостоящие операции и даже ajax-запросы. Пока что, просто убедимся, что вызов setState родителя - перерисует дочерние компоненты. Для этого предлагаю создать обработчик onClick на фразе "Всего новостей".
Попробуйте сами.
Задача: Необходимо добавить компоненту <News />
свойство состояния - counter, в котором будет хранится количество кликов по фразе "всего новостей". То есть обычный автоинкремент. Это свойство нужно выводить после количества новостей в обычном параграфе (<p>
). Будет выглядеть так:
В решении важно использовать this.setState({counter: ++this.state.counter})
, об этом мы подробнее поговорим после решения, которое представлено ниже в виде подсказок и полностью.
Подсказка #1: добавьте свойство state в компонент <News />
для создания начального состояния.
Подсказка #2: добавьте обработчик onClick с функцией, которая будет увеличивать cчетчик (следовательно, изменять state, следовательно, вызывать this.setState... ).
Решение: Полный код компонента <News />
Проверьте в браузере. Если вы не удаляли console.log из компонента <Article />
- на каждый клик по фразе "Всего новостей", в консоли будет появляться по 4 "перерисовки".
Поговорим о: this.setState({counter: ++this.state.counter })
Почему же, было важно использовать именно префиксную запись ++, а не постфиксную? Сначала вспомним теорию:
++ перед переменной (префикс) - сначала увеличивает ее на 1, а потом возвращает значение;
++ после переменной (постфикс) - сначала вернет значение, а потом увеличит значение переменной;
В таком случае, мы должны были бы потерять всего 1 клик, не так ли? Проверьте в консоли следующим образом: откройте вкладку React в консоли, выберите компонент <News />
, начните кликать на фразу "Всего новостей"
Изменяется ли значение counter, если используется префиксная запись?
Да, изменяется
Изменяется ли значение counter, если используется постфиксная запись?
Нет, не изменяется вообще. (убедитесь сами)
Ответ кроется в официальной документации:
setState() - не изменяет this.state немедленно, а создает очередь изменений состояния. Доступ к this.state после вызова метода, потенциально может вернуть имеющееся (что равносильно - бывшее) значение.
Самое время крикнуть - верните мои деньги назад, и уйти... Но, не все так плачевно. Теперь вы знаете об этой особенности, и будете если что вооружены. Зачем так сделано? Вероятно, для оптимизации работы библиотеки в целом.
Вообще state у компонентов используется не часто. С появлянием flux - подхода (здесь я прослезился и не стал переписывать в 2k18м году), коммьюнити стало перемещаться на сторону stateless подхода, когда state не используется вообще (за исключением редких моментов). Мой любимый игрок данного лагеря - Redux, о котором я тоже написал подробное руководство на русском (руководство еще не переписано на современный лад, но теорию почитать можно).
Почему сейчас мы не изучаем Redux, стоит ли бросить все и прочитать другой туториал? Определенно - нет. Продолжайте изучение данного курса.
Ситуация в 2018м году:
Есть не только Redux, но и MobX и прочие игроки. Однако Redux до сих пор остается моим любимым;
React для управления состоянием приложения в целом, добавил Context API, о котором мы еще поговорим;
Чистый flux не используется;
Исходный код с console.log'ами и обработчиком кликов на фразе "Всего новостей".
Last updated