Как обновлять объекты и массивы в state без мутаций?
Главное правило работы со state в библиотеке React заключается в категорическом запрете на прямые мутации текущих данных. Если вы измените свойство объекта или элемент массива «на месте», React просто не заметит этих изменений, поскольку ссылка на объект в памяти останется прежней, а значит, компонент не выполнит повторный рендеринг и интерфейс пользователя останется старым.
Чтобы обновлять сложные структуры данных корректно и без побочных эффектов, необходимо всегда создавать их новые копии. Для работы с объектами используется синтаксис оператора расширения, который позволяет скопировать старые свойства и перезаписать только нужные поля, например через конструкцию setS(prev => ({ ...prev, a: 1 })).
Для добавления новых элементов в массивы также применяется оператор spread, который разворачивает старый массив в новый с добавлением элемента: setA(prev => [...prev, item]). Если же вам нужно удалить элемент из массива без мутации исходного списка, следует использовать метод filter, который возвращает совершенно новый массив, содержащий только те элементы, которые удовлетворяют заданному условию.
В тех случаях, когда структура состояния становится слишком глубокой и вложенной, ручное копирование через операторы распространения может сильно загромождать код. Для упрощения работы с такими данными разработчики часто подключают специализированные библиотеки, такие как Immer, которая позволяет писать код так, будто вы мутируете данные напрямую, но под капотом создает безопасные неизменяемые копии.