Update a nested value immutably
Updating nested state immutably by hand produces a pyramid of spread operators, and getting it wrong either mutates state or copies everything, defeating the reference checks that React.memo and useMemo rely on.
Implement updateIn(source, path, updater). path is an array of segments: strings are object keys, numbers are array indices. Walk to the end of the path, call updater with the value found there, and return a new structure in which that position holds the returned value. Copy only the containers along the path: any branch you did not walk into keeps its original reference, so result.untouched === source.untouched. Arrays stay arrays and objects stay objects. If a segment along the path is missing, create the container the *next* segment needs — an array when that segment is a number, a plain object otherwise — and call updater with undefined at the end. An empty path means the whole value: return updater(source). The input is never modified.
Arguments
sourceany- The root value to walk into. Not modified.
pathArray<string | number>- Segments to walk. Strings are object keys; numbers are array indices.
updater(current) => any- Called with the value at the end of the path. Its return value is stored at that position.
Returns
any — A new structure identical to source except at the path, which holds updater's return value. Untouched branches keep their original references.
Examples
updateIn({ a: { b: { c: 1 } } }, ["a", "b", "c"], (n) => n + 1);
// { a: { b: { c: 2 } } }updateIn({ list: [1, 2, 3] }, ["list", 1], (n) => n * 10);
// { list: [1, 20, 3] } — number segments keep the array an array
updateIn({}, ["xs", 0], () => "first");
// { xs: ["first"] } — missing containers are created based on the next segmentWhat it has to do
- Treat string segments as object keys and number segments as array indices.
- Return a new structure with the value at the path replaced by
updater's return value. - Share references for every branch not on the path.
- Keep arrays as arrays, and create missing containers based on the next segment's type.
- Return
updater(source)for an empty path, and never mutate the input.
Stuck? The javascript course covers everything this challenge needs.
- 1.replaces a deeply nested value
- 2.shares references for untouched branches
- 3.updates an array index and keeps it an array
- 4.creates missing containers along the path
- 5.does not mutate the source
These assertions run in your browser the moment you hit Run. Pass all of them to claim the XP.
Discussion
Sign in to postNo comments yet. Be the first to say something.