Composition path · React · 56 layers

React: HOC, hooks, and the mount pipeline

withAuth wraps Page. Page renders Form and Profile. The contract — hooks, state, props — links into Form. Pan down: the rest of the hooks, then lifecycle as a function pipeline and as class methods, mapped across. Click Form, Type "H", or DidMount vs useEffect.

Click a shape or a question

Questions this tree answers

Typing · one object per key · input is not debounced

Hooks · state · props
props
hooks · state
events
HOC → page → children
Operation
View data
Fiber architecture
Call stack
Hook list on Form Fiber
Heap / references
Reconcile + commit
GC / reachability
Hooks catalog
rules of hooks
effects · refs
identity · shared
concurrent · also
Lifecycle — function and class
function: mount · update · unmount
class: constructor → unmount
HOC wrapsoperationview datadon’t extendevents updon’t callwritesnot yetEvents uponChangemaps to Form Fibermaps tochildchildrender → Fiber architectureref → B...prevthis render still sees Aafter commitdeps changethen commiton updatesame pipeline≈ []≈ cleanupDoes not: subclassAllows: Input controlAllows: Button controlAllows: props only3. props4. hooksstate5. events16. Allows: map to Fiber archAllows: walk the Fiber treeAllows: schedule Form FiberDoes not: a stack per FiberAllows: run handleChangeAllows: call setFormDoes not: keep the frame17. Allows: Hook #1 formAllows: Hook #2 loadingAllows: Hook #3 effect18. Allows: Object B currentAllows: object spreadDoes not: mutate AAllows: same input identity19. Allows: patch valueDoes not: rebuild the pageAllows: keep reachable BAllows: A eligibleDoes not: delay the inputAllows: top-level orderDoes not: hook in ifAllows: after paintAllows: before paintAllows: keep a resultDoes not: memo everythingAllows: start at Form()Does not: call Form() to unmountAllows: construct onceDoes not: fetch in constructor
hocwithAuth(Page)
  • fn(Component) → Component
rejectedclass extends Page
  • is-a · not the model
  • don’t subclass
parent pagePage
  • owns profile · two children
  • Form + Profile · not nested
operationfunction Form()
  • edit profile · owns form state
  • click → hooks · Fiber · heap
control<input>
  • value={form.name}
  • no hooks of its own
control<button>Save</button>
  • onSave() → Page
  • no hooks
view datafunction Profile()
  • name · email · city
  • props only · no hooks
  • sibling of Form, not a child
runtimeReact calls Form(props)
  • builds the object
  • dials on re-render
wrongForm() yourself
  • you are not the caller
  • does not refresh
inputprops { profile, onSave }
  • named fields from Page
  • Form reads · Profile reads
forbiddenprops.name = "H"
  • notifies no one
  • Page still holds it
diffprev | next
  • new object, new call
  • in-place edit lies
fallbacksize = "md"
  • default parameter
  • still a prop
hook slotuseState(form)
  • memory on Form Fiber
  • [value, setter]
wronglet form = {}
  • dies with this call
  • no re-render
this renderform = A (frozen)
  • const does not change
  • next call sees Object B
schedulesetForm(...)
  • queues a render
  • not assignment
not yetconsole.log still A
  • setter did not write through
  • this const is frozen
one painttwo setters → one render
  • same event, one tree
  • no frame in between
copy{ ...form, name }
  • replace the object
  • nested copy if nested
copy[...items, x]
  • replace the array
  • map / filter to change
from prevsetForm(prev => …)
  • when next depends on prev
  • batches and async
computefullName = first + last
  • not a second slot
  • always matches source
forbiddenitems.push(x)
  • same reference · skip lies
listeneronChange={handleChange}
  • pass the function
  • do not call it in JSX
wrapperSyntheticEvent
  • same shape, every browser
  • preventDefault · nativeEvent
closureonClick={() => save(id)}
  • wrap to pass extra args
  • event is not your id
rejectedform + storedName
  • two truths, they drift
  • don’t mirror props
fiberApp Fiber
  • root of this tree
  • child → Layout
fiberLayout Fiber
  • child of App
  • sibling walk continues
scheduledForm Fiber
  • render lands here
  • hook list hangs off this
fiberInput Fiber
  • child of Form
  • no hook list
framehandleChange(event)
  • one JS stack
  • gone after return
settersetForm(prev => …)
  • allocates Object B
  • this render still sees A
batchUpdate queue
  • marks Form Fiber dirty
  • arrow goes to architecture
hook #1useState(form)
  • reads this slot
  • does not re-init
hook #2useState(loading)
  • same Fiber
  • not Layout’s hooks
hook #3useEffect(...)
  • after commit
  • debounce lives here
oldObject A
  • name: ""
  • previous snapshot
currentObject B
  • name: "H"
  • Hook #1 points here
copyObject spread
  • ...prev then name: "H"
  • not map()
prev treeInput value=""
  • last commit
next treeInput value="H"
  • this Form() return
commitReuse DOM · patch value
  • same type · position · key
  • not a new page
unreachableObject A eligible for GC
  • no live ref from Hook #1
  • engine collects later
timeline"" → … → Hitesh
  • one current object
  • older eligible
side effect500ms debounce → API
  • input updates now
  • saveProfile waits
call orderTop of Form(), same order
  • list has no names
  • index is identity
forbiddenif (x) useState(0)
  • list changes shape
  • steal the wrong slot
forbiddenhooks in a loop
  • count must be stable
  • extract a child Fiber
extractuseDebounced(form)
  • starts with use
  • calls other hooks
  • no extra DOM node
after paintuseEffect(fn, deps)
  • side effect, not render
  • Hook #3 pulled out
when[] · [form] · missing
  • [] mount · [x] update
  • no array = every render
returnreturn () => clearTimeout
  • before next effect
  • and on unmount
before paintuseLayoutEffect
  • measure · no flicker
  • blocks paint — rare
mutable boxuseRef(null)
  • write .current
  • does not re-render
DOMref={inputRef}
  • filled after commit
  • null on unmount
keep resultuseMemo(() => total, [items])
  • identity or expensive
  • deps are Object.is
keep functionuseCallback(fn, [id])
  • for a memoized child
  • not every onClick
rejectedmemo everything
  • identity is not speed
  • measure first
ambientuseContext(Theme)
  • nearest Provider
  • not for cartCount
transitionsuseReducer(reducer, init)
  • dispatch a fact
  • when updates are related
external storeuseSyncExternalStore
  • subscribe outside React
  • app code rarely
a11yuseId()
  • stable server / client
  • not a list key
non-urgentuseTransition()
  • keep the input urgent
  • defer the heavy list
stale-okuseDeferredValue(query)
  • lagging copy of a value
  • input stays live
alsouseImperativeHandle · insertion · optimistic
  • know the names
  • not Form’s daily path
  • use · useActionState · useDebugValue
1 renderForm()
  • pure · no fetch
2 commitCommit DOM
  • refs fill here
3 layoutuseLayoutEffect
  • before paint
4 paintBrowser paint
  • user sees "H"
5 effectuseEffect
  • [] = on mount
updateCleanup → re-run
  • same Fiber · new snapshot
  • deps gate the effect
unmountRun cleanups · drop Fiber
  • no last Form()
  • abort / clearTimeout
devStrict Mode double
  • setup → cleanup → setup
  • finds missing cleanup
identitykey change = remount
  • new Fiber, fresh state
  • not an effect copy
pipelineMount 1–5 · update + cleanup · unmount cleanup
  • no method names
  • the hooks are the methods
onceconstructor(props)
  • this.state = …
  • no fetch here
raregetDerivedStateFromProps
  • prefer key / derive
  • before render
purerender()
  • same job as Form()
  • may call twice
after first commitcomponentDidMount
  • DOM exists
  • ≈ useEffect([])
skip?shouldComponentUpdate
  • PureComponent ≈ shallow
  • ≈ memo
before mutategetSnapshotBeforeUpdate
  • read old DOM
  • ≈ useLayoutEffect
after commitcomponentDidUpdate(prevProps, prevState)
  • compare prev yourself
  • ≈ useEffect(deps) · unguarded setState loops
last callcomponentWillUnmount
  • clear · abort · no setState
  • ≈ effect cleanup
mapDidMount ↔ useEffect([]) · WillUnmount ↔ cleanup
  • constructor ≈ useState / useRef
  • render ≈ Form() · gSBU ≈ useLayoutEffect
  • DidUpdate ↔ useEffect(deps)
72%

Click a box · three arrows off a layer are what it allows

What React is