The copy that was not a copy
Spread copies one level. Everything underneath is still shared, and that is where the state bug is hiding.
Object spread and Array.from produce a new container whose slots hold the same references as the old one. Change a top-level field on the copy and the original is untouched. Change something two levels down and both see it, because both are looking at the same nested object. This is the single most common source of "I updated state and nothing re-rendered" and "I updated state and something else changed too".
structuredClone handles the deep case for plain data, Dates, Maps, Sets, ArrayBuffers and cycles, and throws on functions, DOM nodes and class identity. It is built in, it is fast enough, and it is the right default when you genuinely need an independent tree. JSON round-tripping is the wrong default: it silently converts Dates to strings, drops undefined and functions, turns NaN and Infinity into null, and explodes on cycles.
The better move is usually to avoid needing the copy. If you only ever produce new objects along the path you are changing, new root, new branch, same untouched siblings, you get correctness and cheap equality checks at once. That pattern is called structural sharing, and it is what every state library you will meet in Phase 04 is doing under the surface.
You should now be able to
- Distinguish a shallow copy from a deep one
- Choose a copying strategy that matches the shape of the data
Loading…