Зачем нужна обертка в виде объекта для setState в React
Что проверяют
Понимаете ли вы, как React обновляет состояние: что setState делает с переданным объектом, зачем бывает функция вместо объекта и чем это отличается у хуков. Следом почти всегда дают код с тремя вызовами setState подряд и спрашивают, на сколько вырастет счётчик.
Как отвечать
В классовом компоненте this.state всегда объект, а setState принимает не новое состояние целиком, а объект с изменениями. React поверхностно сливает его с текущим состоянием: this.setState({ isActive: true }) меняет одно поле и не трогает остальные. Слияние идёт только по верхнему уровню, вложенный объект заменяется целиком, поэтому его копируют через spread.
Дальше вторая форма, ради которой вопрос часто и задают:
- объект:
this.setState({ count: this.state.count + 1 })читает значение в момент вызова. Обновления батчатся, и три таких вызова в одном обработчике дадут +1, а не +3; - функция-апдейтер:
this.setState(prev => ({ count: prev.count + 1 }))получает состояние с учётом предыдущих обновлений в очереди, три вызова дадут +3.
С React 18 автоматический батчинг работает везде: в промисах, таймаутах и нативных обработчиках, а не только в событиях React. Для действия после применения состояния у классов есть колбэк вторым аргументом и componentDidUpdate.
У хуков правило другое: сеттер useState не сливает, а заменяет значение. Объект в состоянии копируете сами: setUser(prev => ({ ...prev, name })). Если передать тот же объект после мутации, React сравнит ссылки через Object.is и может пропустить рендер.
Где спотыкаются
Говорят, что setState асинхронный, и пытаются написать await. Промис он не возвращает: обновление откладывается и группируется, а актуальное значение читают в апдейтере или после рендера.
Мутируют состояние напрямую, например this.state.items.push(x). Такое изменение может перезаписать следующий setState, а PureComponent и мемоизированные дети его не заметят, потому что ссылка на массив не поменялась.
Переносят привычку классов на хуки и передают в сеттер useState только изменённое поле. Остальные поля объекта при этом пропадают.