useSetLoading saved progress…

useSet

Build a custom React hook that manages a unique collection of values. A Set is the natural fit when you need membership without duplicates — selected row ids, expanded panel keys, a set of active filters. But a Set is mutable: set.add(x) and set.delete(x) change the existing object in place, and React decides whether to re-render by checking whether you handed it a new value, not by inspecting the contents. useSet(initialValues) owns the set and hands back the current set plus four helpers that change it the right way: add, remove, has, and clear.

Signature

function useSet<T>(initialValues?: Iterable<T>): {
  set: Set<T>;
  add: (item: T) => void;
  remove: (item: T) => void;
  has: (item: T) => boolean;
  clear: () => void;
};

initialValues is any iterable (usually an array) and defaults to empty. add inserts a member; remove drops one; has returns whether a value is currently a member; clear empties the set back to an empty Set.

Examples

function TagPicker() {
  const { set, add, remove, has } = useSet(['react']);

  const toggle = (tag) => (has(tag) ? remove(tag) : add(tag));

  return ['react', 'vue', 'svelte'].map((tag) => (
    <button key={tag} aria-pressed={has(tag)} onClick={() => toggle(tag)}>
      {tag}
    </button>
  ));
}
// 'react' starts pressed; clicking 'vue' adds it; clicking 'react' again removes it
// Each mutating helper returns a brand-new Set; the old one is never changed.
const { set, add, remove, has } = useSet([1, 2]);
add(3);       // set is now {1, 2, 3}
add(3);       // still {1, 2, 3} — Sets ignore duplicates
remove(1);    // {2, 3}
has(2);       // true

Notes

  • Never mutate the set in place. set.add(item) changes the existing Set 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 goes stale.
  • Each mutating helper makes a new Set. Copy first with new Set(prev), then add or delete on the copy, and hand React that fresh object.
  • Helpers must survive batched updates. React groups several helper calls in one event into a single re-render, so updates have to stack correctly rather than each reading the same stale snapshot.
  • Duplicates are handled for you. Adding a value that is already a member leaves the set unchanged — that is what a Set is for. Removing a value that is not present is also a no-op, not an error.
  • 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…