New to React? Used to following the road map of code to know what a piece of code is doing? Get ready for a wild ride — and forget what you thought you knew. React asks you to rethink how you understand the flow of your code. If you're used to tracing execution line by line to see how a program reaches its final state, React will feel like a different world.
React components follow a lifecycle—a series of phases from creation to updates and eventual removal. Understanding this lifecycle is key to predicting how and when your code will run.
In your React journey, you are not fully in control of your path to completion. React can be thought of as a series of intents. The code declares its intent, and React acts upon those declarations according to its own rules. It is not necessarily linear. Nor does it necessarily execute only once on the way to a final state. What does this mean? You describe what you intend the UI to look like, and React decides how and when to make that happen. Your components declare their desired outcome, and React orchestrates the updates according to its own rules. React might re-run functions, re-render components, or re-evaluate state multiple times as it works toward the final state.
The Mental Model Shift
If you're used to tracing execution line by line to understand what a program is doing, hooks will feel unfamiliar at first. Traditional code follows a road map—line 2 runs after line 1, and you can follow the path to the final state. React works differently. Hooks are declarations of intent, not instructions.
When you call a hook, you are not telling React what to do right now. You are telling React what you need, and React acts on that declaration according to its own rules—at a time you don't directly control.
This means:
- Execution is not necessarily linear. Code written earlier in the function may run later than code written below it.
- Components may run more than once. React can re-run your component function, re-evaluate state, and re-render the UI multiple times as it works toward the final result.
- You are not fully in control of the path to completion. React orchestrates the updates.
Hooks as Declarations of Intent
Each hook call is a declaration:
useState()— "I intend to have a persistent variable. Here's what to call it and its setter."useRef()— "I intend to have a persistent container. Fill it in after rendering."useEffect(() => {...}, [])— "I intend for this to run after the first render."
React reads all of these declarations, builds the component, and fulfills each intent at the appropriate moment in its lifecycle.
For a practical summary and detailed guide to individual hooks, see React Hooks — Practical Summary.
React's Rendering Contract
React renders components using a "fill it or remodel it" approach (officially called reconciliation in React's documentation):
- If the space is empty, fill it—React creates a new native component and assigns it an ID.
- If the space is filled, remodel it—React updates only what has changed (props, state) without destroying and recreating the component.
This means native component IDs remain stable across re-renders. React updates the props, not the underlying instance.
The Three Core Hooks (and What They Intend)
| Hook | Declaration of Intent | When React Fulfills It |
|---|---|---|
useState |
"Give me a persistent variable and a setter" | On every render; setter triggers a re-render |
useRef |
"Give me a persistent container; fill it after render" | Container persists; React populates .current |
useEffect |
"Run this after the render is complete" | After each render (controlled by dependencies) |