useReducer
A cart as one pure reducer with typed actions: dispatch, lazy init, testing without React, and when React bails out.
ReadModule 3 of 7
These are the APIs you don't reach for every day. Each one exists because React's default model sometimes isn't enough:
useReducer puts scattered updates into one pure function.createPortal escapes the DOM structure without leaving the React tree.useLayoutEffect and flushSync deal with "the DOM hasn't caught up yet".useImperativeHandle turns a ref into a small command API.useSyncExternalStore reads state React doesn't own.The examples are all part of the product store: a cart reducer, a theme and cart context, a "Quick view" dialog, a shipping tooltip, a coupon field, a wishlist, and a cart store shared by two React roots. Every log, render list and painted frame was recorded by running the store in Chrome (examples/product-store/src/lessons/apis).
Reaching for one of these is a sign you've hit a real boundary. Two of them pair up: useLayoutEffect reads the DOM before paint, and flushSync writes it before your next line of code.
Read them in order. Each one builds on the ones before it.
A cart as one pure reducer with typed actions: dispatch, lazy init, testing without React, and when React bails out.
ReadcreateContext, a provider and use(): skip the prop drilling, and know exactly which components re-render.
ReadRender a dialog into document.body so a clipping parent can’t hide it; events and context still follow the React tree.
ReadMeasure before the browser paints: the recorded frame where a useEffect tooltip covers its button.
ReadExpose a small set of methods (focus, clear) on a ref, for commands that don’t fit in state.
ReadRead state React doesn’t own (the browser, a plain JS store) safely, with stable snapshots and a server value.
Read