Hello! Welcome back to our series on React's rendering model.
In our last lesson, we explored the critical role of the key prop. We saw how it provides a stable identity for components, which is essential for efficient list updates and correct state management. Crucially, you learned that changing a component's key is a powerful technique to force React to unmount the old instance and mount a new one.
Today, we'll formalize those concepts. This lesson focuses on the learning outcome: Describe the abstract component lifecycle phases (mounting, updating, unmounting) and how React manages them.
We will go beyond simply listing lifecycle events and explore the conceptual model React uses. You'll learn about:
- The three primary phases: Mounting, Updating, and Unmounting.
- The more granular "Render" and "Commit" phases that provide a deeper look into React's process.
- How React internally tracks and manages components through these phases.
- How modern hooks, particularly
useEffect, allow us to tap into these lifecycle moments.
Your experience with software development will be valuable here, as the component lifecycle mirrors familiar concepts of object instantiation, state updates, and resource deallocation.
The Three Abstract Phases of a Component's Life
Every component in a React application goes through a journey. We can simplify this journey into three distinct, high-level phases.
Understanding React's Component Lifecycle (Hooks Way)
To start, let's get a clear definition of these phases. This article provides an excellent, concise overview.
Read the sections titled 'What Do We Mean by “Lifecycle”?' and 'The Three Big Stages'. These sections define the lifecycle concept and introduce the Mounting, Updating, and Unmounting phases.
As you just read, the three phases are:
- Mounting (Birth): This happens when a component is being created and inserted into the DOM for the first time. It's the one-time setup phase where you might initiate data fetching or set up subscriptions.
- Updating (Life): This occurs whenever a component re-renders due to a change in its props or state. The component's function is called again, and React updates the DOM to reflect the new output.
- Unmounting (Retirement): This is the final phase, where the component is being removed from the DOM. It's the essential cleanup phase for releasing resources like timers or event listeners to prevent memory leaks.
To see these phases in action, the following video provides a helpful visual walkthrough.
The React Lifecycle: Simply Explained!
This video uses a whiteboard analogy to illustrate the three lifecycle phases and how a component function moves through them.
Watch from 01:03 to 06:27. Focus on how the narrator outlines the initial render (mount), update, and exit (unmount) stages and how they all ultimately result in a 'browser paint'.
A Deeper Look: The Render and Commit Phases
To truly understand how React manages the lifecycle, we need to break down the "Mounting" and "Updating" processes into two more granular stages: the Render Phase and the Commit Phase. This distinction is central to modern React and its performance characteristics.
Blogged Answers: A (Mostly) Complete Guide to React Rendering
Let's explore this crucial distinction. This article offers a very precise, technical explanation.
Read the subsection titled 'Render and Commit Phases'. Pay close attention to the separation of work: the 'Render phase' is for calculating changes, and the 'Commit phase' is for applying them. Note the timing of useEffect relative to these phases.
Here's a summary of that critical information:
-
Render Phase:
- React executes your component function (e.g.,
MyComponent(props)). - It reconciles the new element tree with the old one (the "diffing" we discussed previously).
- This phase must be pure. You cannot have side effects like DOM manipulation or network requests here. React may pause, abort, or re-run this phase (a feature of Concurrent Rendering).
- React executes your component function (e.g.,
-
Commit Phase:
- Once the render phase is complete and React has a list of changes, it applies them to the DOM.
- This phase is synchronous and cannot be interrupted.
- After the DOM is updated, React runs hooks like
useLayoutEffectsynchronously, and then schedulesuseEffecthooks to run asynchronously shortly after. Side effects are performed here.
The diagram below, while using older class component syntax, perfectly visualizes this separation. Notice how methods like render are in one "Render Phase" block, while methods that interact with the DOM like componentDidMount and componentDidUpdate are in a separate "Commit Phase" block.
How React Manages Component Instances
So how does React keep track of all this? It's not magic; it's a well-defined internal architecture.
When React renders your app, it builds an internal tree of objects called Fibers. Each fiber corresponds to a component instance and acts as a unit of work. This fiber object is where React stores the component's type, props, state, and its relationship to other components (parent, child, sibling).
This fiber tree is the "memory" of your application's UI. When an update is triggered (e.g., setState is called), React walks this tree to figure out which components need to re-render.
- On Mount: When a component appears for the first time, React creates a new fiber object for it, runs its code (render phase), creates the DOM nodes, and adds them to the document (commit phase).
- On Update: When a component's state or props change, React schedules an update on its fiber. It then begins a new render phase, calling the component function again and comparing the output to the previous render. If there are differences, it proceeds to the commit phase to update the DOM.
- On Unmount: When a component is no longer rendered by its parent (due to conditional logic or a changed
key), React finds its fiber, runs any necessary cleanup logic, and removes the associated DOM nodes during the commit phase.
The following video explains this concept of "component instances" that React manages.
How Does React Actually Work? React.js Deep Dive #1
This video explains the distinction between React elements, components, and component instances, which is key to understanding the lifecycle.
First, watch from 00:33 to 05:34. This part clarifies that what we write (components) produces elements, and React uses these to manage 'instances' which hold state and lifecycle. Then, watch from 07:53 to 09:12. This section reinforces a concept from our last lesson: when element types differ, React destroys the old instance and its state, triggering the unmount/mount lifecycle.
Hooking into the Lifecycle
With this conceptual understanding, we can now see how modern hooks provide a way to execute code at specific points in the lifecycle. The primary tool for this is the useEffect hook.
The useEffect hook's behavior is controlled by its dependency array:
| Hook Usage | Maps to Lifecycle Phase |
|---|---|
useEffect(() => { ... }, []) |
Mounting: Runs once, after the initial render and commit. |
useEffect(() => { ... }, [dep]) |
Updating: Runs after commit whenever dep has changed. |
useEffect(() => { return () => { ... } }) |
Unmounting: The returned cleanup function runs just before the component unmounts. It also runs before the effect re-runs on an update. |
Let's watch a video that walks through each phase with code examples.
The React Lifecycle: Simply Explained!
This video connects the abstract lifecycle phases directly to the code you write, showing what happens during mount, update, and unmount.
Watch from 06:27 to 23:06. The video covers: Mounting (06:27): How values are initialized and useEffect is scheduled. Updating (11:42): How the function re-runs and values are recomputed. Unmounting (17:55): How cleanup functions are executed to release resources.
A Note on Strict Mode
You may have noticed in development that your useEffect hooks sometimes run twice on mount. This is not a bug; it's a feature of React's Strict Mode designed to help you write more robust components.
In development, Strict Mode intentionally performs a quick mount -> unmount -> mount cycle for components. This helps flush out bugs related to improper cleanup. If you forget to clean up a subscription in your effect's cleanup function, this double-invocation will often make the resulting memory leak obvious.
Understanding React's Component Lifecycle (Hooks Way)
For a clear explanation of this behavior, let's return to the 'Lifecycle (Hooks Way)' article.
Read the section 'React 19, Strict Mode, and Double Invocations'. It explains what's happening and why this behavior is beneficial for catching bugs.
Conclusion
In this lesson, we deconstructed the React component lifecycle, moving from a high-level abstract model to the underlying mechanics.
Key Takeaways:
- The component lifecycle consists of three main phases: Mounting (creation), Updating (re-rendering), and Unmounting (destruction).
- React's rendering process is divided into a Render Phase (pure, for calculation) and a Commit Phase (impure, for DOM updates and side effects).
- React manages component instances using an internal data structure called the Fiber tree, which tracks the state, props, and lifecycle status of every component.
- The
useEffecthook is the primary tool in modern React for running code during these lifecycle phases, controlled by its dependency array and cleanup function. - Strict Mode intentionally double-invokes mount/unmount in development to help you find bugs in your cleanup logic.
What's Next?
Now that you understand how a single component lives and breathes, the next logical step is to understand how components interact with each other. In the next lesson, we will explore one of React's core principles: unidirectional data flow and how props are passed down the component tree. This will explain how data moves through your application and triggers the update lifecycles we discussed today.