Почему второй setState не получает измененное значение state в React и как это исправить
Что проверяют
Понимаете ли вы, что состояние в React это снимок конкретного рендера, а не обычная переменная, и знаете ли функциональную форму обновления. Заодно проверяют, представляете ли вы, когда новое значение вообще становится доступным.
Как отвечать
Сеттер не меняет переменную на месте: он ставит обновление в очередь и планирует перерисовку. Внутри текущего вызова функции значение остаётся тем, с которым компонент отрендерился, поэтому два вызова подряд от одного снимка дают прибавку на единицу, а не на две.
setCount(count + 1);
setCount(count + 1); // оба считают от одного и того же count
setCount((prev) => prev + 1);
setCount((prev) => prev + 1); // а так получится плюс дваФункция обновления получает значение с учётом уже поставленных в очередь изменений, поэтому она нужна везде, где новое состояние вычисляется из старого. В классовом компоненте приём тот же: this.setState((prev) => ({ count: prev.count + 1 })).
Полезно добавить два уточнения. React объединяет несколько обновлений в одну перерисовку, включая вызовы из промисов и таймеров, так что промежуточного рендера между двумя сеттерами не будет. И функция обновления обязана быть чистой: в строгом режиме она вызывается дважды, поэтому менять внутри неё внешние объекты нельзя.
Где спотыкаются
Читают состояние сразу после вызова сеттера и удивляются старому значению. В этом рендере оно уже не изменится. Если на новое значение надо среагировать, считайте его прямо из выражения либо ловите эффектом, где оно указано в зависимостях.
Меняют состояние по месту: добавляют элемент в существующий массив и передают его же в сеттер. Ссылка прежняя, React сравнивает по ней и перерисовку не планирует. Нужен новый массив или объект.
Обходят проблему через ссылку из useRef или переменную вне компонента, чтобы значение было всегда свежим. Такие значения не вызывают перерисовку, и интерфейс расходится с данными. Ссылка уместна для того, что не рисуется: таймера, идентификатора запроса, предыдущего значения.