🟠 [Scene 1] Hook / Attention Grab (0–15s)
“Here’s something that confuses a lot of developers:
If React components are just JavaScript functions — and JavaScript functions forget
everything when they finish —
then how does useState remember our data across multiple renders?”
👉 That’s not magic. It’s one of the most important internal mechanisms of React.
🔵 [Scene 2] Let's Start from Scratch (15–45s)
Before jumping into useState, let’s understand something really basic.
In JavaScript, if you define a function and call it, all variables declared inside that function
exist only while the function is running.
Once the function ends, all of its local memory is gone.
Example:
js
CopyEdit
function sayHello() {
const name = "Prateek";
console.log("Hello", name);
sayHello(); // works
sayHello(); // works again, but it forgets the last value
Here, the variable name is created and destroyed every time sayHello() is called.
✅ What it means:
When we say "it forgets the last value", we’re talking about how JavaScript functions
handle variables.
Each time a function runs, any variable declared inside the function using let, const, or var
only lives during that one execution.
So the value from a previous call doesn't carry over to the next one.
➡️Even though we call sayHello() twice, the function doesn’t remember the first call.
It creates a new name variable each time and assigns it "Prateek" again.
So:
It works — because it runs properly each time.
But it forgets the last value — because it doesn’t retain any memory of what
happened in the previous call.
🧠 So What About React Components? (45–60s)
React components are also just functions.
React calls your component function every time it wants to render or re-render something
on screen.
So theoretically, any variable inside a component should also reset every time it renders.
But that doesn’t happen with useState. Let’s see this in action.
💻 [Scene 3] Code Example - The Mystery of useState (60–80s)
import { useState } from "react";
function Counter() {
const [count, setCount] = useState(0);
console.log("Component rendered with count:", count);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>+</button>
</div>
);
}
🔍 [Scene 4] Line-by-Line Code Explanation (80–150s)
js
CopyEdit
import { useState } from "react";
We’re importing the useState hook from the React library.
➡️A hook in React is just a special function that lets you “hook into” React’s built-in features
— like state, lifecycle, and context.
js
CopyEdit
function Counter() {
This defines our functional component. Remember: this function will be re-run by React
every time the state changes.
js
CopyEdit
const [count, setCount] = useState(0);
This is where things get interesting.
➡️We’re calling the useState hook.
Here’s what happens under the hood:
The first time this component renders, React stores the value 0 in an internal
memory.
It returns an array of two things:
1. count: the current value of that state.
2. setCount: a function to change that value.
Even though this function (Counter) might be re-run 100 times, count will not reset to 0,
because React remembers it separately.
js
CopyEdit
console.log("Component rendered with count:", count);
This line shows us that the function is indeed being called again and again.
Try clicking the button and watch the log appear again — with updated values.
jsx
CopyEdit
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>+</button>
</div>
);
We show the count on screen. And the button increases it by 1 every time it’s clicked.
But remember: clicking the button causes React to re-run the component — and still, the
count is preserved.
🧠 Spoken Script (Detailed for Video)
“So by now, you’ve seen that useState(0) doesn’t reset to 0 every time your component re-
renders.
That’s cool — but the real question is how React actually pulls this off.
It’s not magic. It’s smart engineering.
Here’s the secret:
When you write const [count, setCount] = useState(0),
React doesn’t store that state inside your function.
Instead, it keeps all of your state values in an internal structure, kind of like an array —
but that array is outside your component.
It’s connected to something called a Fiber Node.
🔵 What is a Fiber Node?
A Fiber Node is just React’s internal data object that keeps track of:
Which component this is
What its props and state are
Which hooks it uses
And how it fits into the overall React tree
📘 You don’t see this in your code — it’s part of React’s internal system.
🧮 The Hook Array System
For each component that uses hooks like useState, React creates a "hook list" (you can think
of it as an array).
Now here’s the trick: React tracks the order of every hook you call — from top to bottom —
every time the component renders.
So behind the scenes, React is doing something like this:
js
CopyEdit
let hookStates = [0]; // holds your count value
let hookIndex = 0; // keeps track of which hook is running
⚙️Let’s Simulate React’s useState Internally
js
CopyEdit
function useState(initialValue) {
const currentIndex = hookIndex; // example: 0
hookIndex++; // move pointer forward
// set the value for the first time if it's undefined
hookStates[currentIndex] = hookStates[currentIndex] ?? initialValue;
const setState = (newValue) => {
hookStates[currentIndex] = newValue;
rerenderComponent(); // triggers re-render
};
return [hookStates[currentIndex], setState];
👉 function useState(initialValue) {
This defines a custom function that behaves like React’s useState.
It takes an initialValue, just like the real useState(0) or useState("hello").
👉 const currentIndex = hookIndex;
hookIndex is a global counter that tracks which hook is being called inside your component.
📌 Example:
If you're using 3 hooks:
js
CopyEdit
const [a, setA] = useState(1); // hookIndex = 0
const [b, setB] = useState(2); // hookIndex = 1
const [c, setC] = useState(3); // hookIndex = 2
React stores their values at index 0, 1, and 2 in an internal array.
👉 hookIndex++;
After assigning the current index, we move the pointer forward so that next hook call refers
to the next position in the memory array.
This is why hooks must be called in the same order on every render — otherwise the index
system breaks.
👉 hookStates[currentIndex] = hookStates[currentIndex] ?? initialValue;
This is the heart of the function.
Let’s break it down:
hookStates is an internal array where React stores state values.
hookStates[currentIndex] returns the current state at this hook’s position.
The ?? operator means:
o “If the current value is undefined, then assign it initialValue.”
📘 This ensures:
On first render, the state gets set to initialValue.
On future renders, the state remains as-is (because it's already defined).
👉 const setState = (newValue) => { ... }
This defines the function that updates the state.
This is exactly like the setCount you get from useState.
👉 hookStates[currentIndex] = newValue;
When setState is called, React replaces the old value in its internal state array.
So if your old count was 0, and you call setCount(5), this line updates the internal memory to
5.
👉 rerenderComponent();
React must now re-render the component so it can reflect the new value in the UI.
In real React, this triggers a render cycle. In our fake simulation, we're just calling a
placeholder function.
👉 return [hookStates[currentIndex], setState];
Just like React's real useState, we return:
The current value stored in memory
The function to update it
🧠 What this means
React does not care about variable names like count or setCount.
It only tracks how many hooks you call and in what order.
So:
The first useState() call always connects to hookStates[0]
The second one, if you had it, connects to hookStates[1]
And so on.
⚠️Why This Rule Exists: "Never call hooks conditionally"
Let’s say you did this:
js
CopyEdit
if (showCount) {
const [count, setCount] = useState(0); // BAD!
On the first render, useState(0) is called — React stores that at position 0.
But on the next render, if showCount is false, React doesn’t call useState() at all.
Now everything breaks — the hook order is messed up.
📛 React will throw an error because the hook memory and the actual calls no longer line
up.
✅ The Golden Rule
React hooks are tracked by position, not by name.
That’s why you must always:
Call hooks unconditionally
Call hooks in the same order on every render
🎥 [Optional Visuals You Can Show On Screen]
Hook Call Hook Memory (React Internal)
useState(0) hookStates[0] = 0
useState("dark") hookStates[1] = "dark"
➡️Hook 0 always maps to the first useState, hook 1 to the second, and so on.
💬 Recap This Section Simply
So when you write useState(0), React saves that 0 outside your function.
Every time your component re-renders, React:
Grabs the value from memory
Moves to the next hook
And gives you the current state value
That’s how state is preserved across renders — even though your component function runs
again and again.