useMapLoading saved progress…

useMap

Build a custom React hook that manages key/value pairs in state. A Map is the natural structure for "look up a value by its key" — a cart keyed by product id, form errors keyed by field name, a selection keyed by row id. But Map is mutable: map.set(k, v) and map.delete(k) change the existing object in place. React decides whether to re-render by checking whether you handed it a new value, not by inspecting the contents — so a mutated Map looks unchanged and the screen goes stale. useMap(initialEntries) owns the Map and hands back the current map plus four helpers that change it the right way: set, remove, get, and clear.

Signature

function useMap<K, V>(initialEntries?: Array<[K, V]> | Map<K, V>): {
  map: Map<K, V>;
  set: (key: K, value: V) => void;
  remove: (key: K) => void;
  get: (key: K) => V | undefined;
  clear: () => void;
};

initialEntries defaults to an empty list when omitted, and accepts either an array of [key, value] pairs or an existing Map. set adds or overwrites an entry; remove deletes the entry for a key; get reads the value for a key (or undefined if absent); clear empties the Map.

Examples

function PriceList() {
  const { map, set, remove, clear } = useMap([['apple', 1]]);

  return (
    <div>
      {[...map].map(([name, price]) => (
        <button key={name} onClick={() => remove(name)}>{name}: {price} x</button>
      ))}
      <button onClick={() => set('banana', 2)}>add banana</button>
      <button onClick={clear}>clear</button>
    </div>
  );
}
// shows apple: 1; "add banana" -> apple: 1, banana: 2; clicking "apple" -> banana: 2
// Each mutating helper returns a brand-new Map; the old one is never changed.
const { map, set, remove, get } = useMap([['a', 1]]);
set('b', 2);     // Map { a => 1, b => 2 }
set('a', 99);    // Map { a => 99, b => 2 }  (overwrites)
get('a');        // 99
get('missing');  // undefined
remove('a');     // Map { b => 2 }

Notes

  • Never mutate the Map in place. map.set(k, v) changes the existing Map and keeps the same reference. React compares the new value to the old by reference, sees no change, and skips the re-render — so the screen freezes.
  • Each changing helper makes a new Map. Copy first with new Map(prev), then apply the change to the copy. new Map(prev) is a shallow copy, which is exactly what reference-equality needs.
  • Helpers must survive batched updates. React groups several helper calls in one event into a single re-render, so updates have to stack on each other rather than each reading the same stale snapshot.
  • get is a plain read. It returns from the current Map and does not trigger a re-render; missing keys return undefined, not an error.
  • Removal is named remove, not delete. delete is a reserved word in JavaScript, awkward to expose as a method, so the hook returns it as remove.
  • You don't need to memoize the helpers for this version — returning fresh functions each render is acceptable. Stabilizing their identity is a separate exercise.
Loading editor…