A list that never changes in place
React re-renders when a reference changes, and memoised selectors skip work when it has not. That only works if updates produce new objects instead of mutating old ones, which is why persistent, immutable collections keep showing up in state libraries.
Implement an ImmutableList class. new ImmutableList(items) takes an optional array and stores a copy of it, defaulting to an empty list; later changes to the array passed in must not affect the list. push(value) returns a new ImmutableList with the value appended, leaving the original untouched. set(index, value) returns a new ImmutableList with that index replaced, or returns the very same instance (this) when the index is negative or past the end. pop() returns a new ImmutableList without the last value, or the very same instance when the list is already empty. get(index) returns the value at an index, or undefined when out of range. size() returns the number of values. toArray() returns a fresh plain array of the values, so mutating what it returns must not affect the list.
Returning the identical instance when nothing would change is the point: callers compare with === to decide whether to re-render.
Examples
const a = new ImmutableList([1, 2]);
const b = a.push(3);
a.toArray(); // [1, 2] — unchanged
b.toArray(); // [1, 2, 3]
a === b; // falseconst a = new ImmutableList([1]);
a.set(5, 9) === a; // true — out of range, no change
a.set(-1, 9) === a; // trueNo-op operations return the same instance, so === is a reliable change check.
const empty = new ImmutableList();
empty.pop() === empty; // true — nothing to removeWhat it has to do
push,setandpopnever modify the list they were called on.setwith an out-of-range index returns the same instance rather than a copy.popon an empty list returns the same instance.- The constructor copies its input, so mutating that array afterwards does not change the list.
toArray()returns a fresh array each time.
Notes
- Each mutation is O(n) because the whole array has to be copied. Real persistent lists (e.g. HAMTs, finger trees) get this down to effectively O(log n) with structural sharing — overkill for most UI state but worth knowing about.
- Returning
thison no-ops is what lets React's reference-equality checks short-circuit — a new array that happens to be equal would still trigger a re-render. - Copy on construction so a caller mutating their input array afterwards cannot reach into your storage.
Stuck? The javascript course covers everything this challenge needs.
- 1.push returns a new list and leaves the original alone
- 2.set replaces a value in the copy only
- 3.an out-of-range set returns the same instance
- 4.pop returns a shorter list and is a no-op when empty
- 5.the constructor and toArray both copy
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.