Inside React’s useEffect: A Deep Dive into the Fiber Source Code
This article dissects the inner workings of React's useEffect hook by tracing its implementation through the React Fiber architecture, from mountEffect and updateEffect functions to the commit phase, revealing how side‑effects are scheduled, created, and cleaned up in modern React applications.
Overview of useEffect in React
The article explains why useEffect was introduced, how it replaces lifecycle methods in class components, and how it separates side‑effects from rendering logic.
Mount and Update Implementations
Both mountEffect and updateEffect are defined in ReactFiberHooks.js. They create a new hook, compute nextDeps, set the sideEffectTag, and store an Effect object via pushEffect. When dependencies have not changed, updateEffect uses NoHookEffect to skip execution.
pushEffect Function
pushEffect(tag, create, destroy, deps)builds an Effect node (a circular linked list) and adds it to the component's updateQueue. The queue is a simple object with a lastEffect pointer, forming a circular list of effects for the component.
Component Update Queue
The componentUpdateQueue holds the effect list. When the first effect is added, the queue is initialized and its lastEffect points to the new effect; subsequent effects are linked in a circular fashion.
Render Flow from ReactDOM to Fiber
Rendering starts with ReactDOM.render, which calls updateContainer in ReactFiberReconciler.js. This function creates a root update and schedules work via scheduleWork. The scheduler eventually invokes renderRoot, which runs the workLoop (or workLoopSync) to process units of work.
performUnitOfWork and beginWork
performUnitOfWorkrepeatedly calls beginWork for each fiber. For function components, beginWork executes renderWithHooks, which runs the component function, registers hooks, and builds the effect list.
Commit Phase
When the render phase finishes, commitRoot is called. It extracts the effect list from the finished work, then runs three phases:
commitBeforeMutationEffects commitMutationEffects commitLayoutEffectsEach phase iterates over the same circular effect list.
commitHookEffectList
The core of useEffect handling resides in commitHookEffectList(unmountTag, mountTag, finishedWork). It retrieves the component's updateQueue, walks the circular list of Effect objects, and for each effect:
If the tag matches unmountTag, it calls the stored destroy function.
If the tag matches mountTag, it calls the stored create function and saves its return value as the new destroy function.
Effects with the NoHookEffect tag are ignored, which explains why some hooks do nothing in certain phases.
Key Takeaways
The article demonstrates how React transforms a declarative useEffect call into a low‑level effect list, schedules it through the Fiber work loop, and finally executes or cleans up side‑effects during the commit phases. Understanding this pipeline clarifies the behavior of dependency arrays, cleanup functions, and the timing of effect execution.
For a visual overview of the Fiber render and commit phases, see the diagram from the React Conf 2017 talk "A Cartoon Intro to Fiber".
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
