Object.assign() и structuredClone() в React стейте: баги с прототипами и Date
Object.assign() и structuredClone() в React стейте: баги с прототипами и Date При immutable-обновлении вложенных объектов в React стейте разработчики часто полагаются на поверхностное копирование через spread или Object.assign(), забывая, что эти методы не сохраняют прототипы и сериализуют Date в строку. Это приводит к тихим багам, которые проявляются только в production при работе с классами или сложными типами. Баг с прототипами: Object.assign() обнуляет методы класса Когда объект содержит экземпляр класса, Object.assign({}, obj) копирует только собственные свойства, игнорируя прототип. Например, методы полностью теряются: class User { constructor(name) { this.name = name; } greet() { return Hi, ${this.name}; } } const original = new User('Alice'); const copy = Object.assign({}, original); console.log(copy.greet()); // TypeError: copy.greet is not a function structuredClone() решает эту проблему для сериализуемых типов, но классы с методами не поддерживаются — код упадет с DOMException. Решение: если в стейте лежат инстансы классов, используйте кастомную функцию глубокого копирования с проверкой прототипа через Object.getPrototypeOf. Баг с Date: structuredClone() превращает дату в строку structuredClone() сериализует Date в строку, как JSON.stringify. После клонирования методы Date (getTime, toISOString) перестают работать: const state = { date: new Date('2024-12-25') }; const clone = structuredClone(state); console.log(clone.date.getTime()); // TypeError: clone.date.getTime is not a function В React стейте это особенно опасно для UI-компонентов, которые полагаются на методы Date (например, календари или таймеры). Типичная ошибка: разработчики думают, что structuredClone() копирует Date нативно, но по спецификации оно заменяет Date на строку UTC. Совет: используйте structuredClone только для данных, которые проходят полный список сериализуемых типов (Map, Set, ArrayBuffer), а для Date заводите отдельный хелпер или библиотеку вроде Immer. Trade-off: поверхностное vs глубокое копирование - Поверхностное копирование (spread, Object.assign) быстрое и простое, но не подходит для вложенных структур с прототипами или ссылочными типами (Date, Map). Риск: мутация общего стора через ссылки. - Глубокое копирование (structuredClone, Immer) безопаснее, но медленнее и несовместимо с некоторыми типами. Практический совет: для production используйте Immer, который корректно работает с прототипами и Date, а structuredClone применяйте только для изолированных данных (cookies, clipboard). Вывод: immutable-обновление в React требует осознанного выбора метода копирования в зависимости от типов данных в стейте, а не слепого использования spread "на всякий случай".