Иногда для того, чтобы научиться делать, нужно научиться тому, чего не следует делать.

Эта статья также доступна в видеоформате.

Примеры из этой статьи доступны для скачивания.

Во-первых, я должен поблагодарить автора Как НЕ реагировать: общие антипаттерны и ошибки в React за вдохновение для этой статьи.

Анти-шаблон

Во-первых, мне неловко узнать, что я долгое время делал что-то не так (в значительной степени с тех пор, как я начал использовать React где-то в 2014 году). Я всегда считал функцию setState синхронной с простой подписью:

setState(nextState)

Фактически, если вы вернулись к документации еще в середине 2015 года и быстро прочитали ссылку, вы придете к такому же выводу. Если бы вы читали дальше, то узнали бы иначе.

примечание: в свое оправдание я также быстро переключился на использование Redux для управления состоянием и поэтому редко (если вообще когда-либо) использовал setState прямо.

Ниже приведен пример компонента с увеличивающимся счетчиком, который я много раз использовал на тренировках; но на этот раз я добавлю тонкий (несколько надуманный) поворот. В этом случае нажатие кнопки Increment дважды вызывает setState.

Код:

примечание: в моем обучающем примере функция increment - это обработчик onClick (один вызов setState на клик) . В этом случае, из-за времени, я никогда не видел проблемы.

Так что же происходит, когда вы нажимаете кнопку Приращение?

Счетчик изменился с 0 на 1.

Если вы считаете, что setState является синхронным (как и я), то вы ожидали, что значение будет равно 2. Каждый вызов setState синхронно изменяет состояние компонента и повторно отображает его.

Очевидно, я ошибался.

Лучший способ

Во-первых, если мы сейчас посмотрим на ссылку для setState, вы даже не увидите сигнатуры setState, к которой я (и многие другие) привык; т.е. непосредственно установка следующего состояния.

Позже он демонстрирует более знакомую (по крайней мере, для меня) сигнатуру, а затем сразу же иллюстрирует антипаттерн, который мы здесь исследуем.

В исправленном коде используется правильная подпись для setState; передача функции обновления increment.

примечание: если вы писали с помощью Redux, этот шаблон аналогичен функциям редуктора, которые вы используете.

В этом коде нажатие кнопки Приращение ведет себя должным образом:

Когда использовать более простую форму

Узнав об этом анти-шаблоне, я подумал, есть ли ситуация, когда безопасно использовать более простую форму setState?

setState(nextState)

Ответ - да, но только если следующее состояние не зависит ни от текущего состояния, ни от свойств.

Дальнейшие действия

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