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 isObject.isequal), it keeps the same state and does not notify.useStore(store, selector = (s) => s, isEqual = Object.is)returnsselector(state)usinguseSyncExternalStore, and re-renders only when the selection changes according toisEqual.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.