FrontendPro

113Implement a fine-grained external state store using useSyncExternalStore without tearing

hardAbout 60 minutesCodingreactstate-managementuseSyncExternalStoreperformance

Problem

Build a tiny Zustand-style store whose components re-render only when the slice they select changes, and that is safe under concurrent rendering (no tearing).

  • createStore(initialState) returns { getState, setState, subscribe }. setState(partial | updater) shallow-merges into a new state object and notifies listeners; if nothing changed (every merged key is Object.is equal), it keeps the same state and does not notify.
  • useStore(store, selector = (s) => s, isEqual = Object.is) returns selector(state) using useSyncExternalStore, and re-renders only when the selection changes according to isEqual.
  • shallowEqual(a, b) compares two objects or arrays one level deep.
const store = createStore({ user: { name: "Asha" }, cart: [], theme: "light" });
function CartCount() {
  const count = useStore(store, (s) => s.cart.length); // ignores theme and user changes
  return <span>{count}</span>;
}
function Header() {
  const { name, theme } = useStore(store, (s) => ({ name: s.user.name, theme: s.theme }), shallowEqual);
  return <h1 className={theme}>{name}</h1>;
}

Requirements

  • A selector that builds a new object every time must not cause an infinite loop or a re-render when the selected values are equal under isEqual.
  • Unsubscribe when components unmount.

Try it yourself

Write your solution, run it, then submit to check it against the tests.

App.jsxReact + DOM

Step-by-step

setState must create a new object ({ ...state, ...partial }) instead of mutating. useSyncExternalStore decides whether to re-render by comparing snapshots with Object.is; a mutated object looks unchanged. Immutable snapshots are also what prevents tearing: a render that started with snapshot A keeps reading A.

Unlock the full solution

What's inside

  • Step-by-step
  • Approach
  • Solution
  • Complexity
  • Edge cases
  • Follow-up questions
  • Tests

Includes 2 code listings, 5 edge cases, 4 follow-up questions.

One-time payment by UPI, card or net banking. Launch price.

All 150 answersOne payment, yours forever