Зачем использовать setState с колбэком в React?
Что проверяют
Понимаете ли вы, что состояние в текущем рендере это снимок, и почему setCount(count + 1) иногда теряет обновления. Под «колбэком» имеют в виду две разные вещи, и хорошо, если вы их разведёте. Следом часто просят объяснить поведение setInterval внутри useEffect.
Как отвечать
Первое значение: функция-обновитель. Вместо значения передаётся функция от предыдущего состояния:
- в хуках:
setCount(c => c + 1). React ставит обновители в очередь и применяет по порядку, поэтому три таких вызова подряд дадут +3, а триsetCount(count + 1)дадут +1: все три читают одно и то жеcountиз замыкания; - в классах:
this.setState(prev => ({ count: prev.count + 1 })), логика та же.
Когда это нужно: новое значение зависит от старого, а обновление вызывается несколько раз за событие или из таймера, промиса, подписки. Классика: интервал в useEffect с пустым массивом зависимостей и setCount(count + 1) застревает на единице, а с обновителем работает и не требует count в зависимостях.
Второе значение: второй аргумент классового setState(updater, callback). Колбэк вызывается после того, как обновление применено и компонент перерисован. У сеттера из useState второго аргумента нет, React выдаст предупреждение. Реакция на новое состояние делается через useEffect, а чаще просто вычисляется в обработчике.
Про «асинхронность» говорите точнее: setState не возвращает промис, он планирует перерисовку. С React 18 обновления батчатся везде, включая промисы и таймауты. Применить обновление немедленно можно через flushSync, но это редкий случай.
Где спотыкаются
Советуют «всегда используйте функцию». Если новое значение не зависит от старого, например текст из инпута, обычный setValue(e.target.value) нагляднее.
Делают в обновителе побочные эффекты: запрос, лог, мутацию. В StrictMode React в разработке вызывает обновитель дважды, и эффект выполнится два раза.
Ждут, что сразу после setCount переменная count станет новой, и читают её следующей строкой.