Learning on Web Dev Open is free for all.

Systems Thinking > What a variable actually holdsThe copy that was not a copy
Phase 03What a variable actually holds134 of 434

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.

Concept14 minAI adversary

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
Ask the community

Loading…