
Bismay.exeπ Missed Day 11? Last time I finally understood why React has Context API, how it solves prop...
π Missed Day 11? Last time I finally understood why React has Context API, how it solves prop drilling, and how multiple components can share the same state without passing props through every level. You can read it here and then come back. I'll wait. βοΈ
After spending the last few days learning about state, Context API, and sharing data between components, I thought I had a pretty solid understanding of React.
Then today's lesson completely changed the way I think about rendering.
I used to assume React somehow "knew" when it should fetch data, start a timer, or clean up resources.
It doesn't.
React only has one main responsibility:
Render the UI.
Anything that needs to happen after rendering is considered a side effect.
And that's exactly why React gives us a hook called useEffect().
By the end of today's class, I realized useEffect isn't just another hook to memorize.
It's React's way of saying:
"If you want something to happen after rendering, tell me exactly when to do it."
Let's dive in. π
Yesterday's big question was:
How can components share state without prop drilling?
Here's what I learned on Day 11:
createContext() creates a shared context.useContext() lets components access that data directly.Today, a completely different question came up.
How does React know when to run code after rendering? π€
Suppose I have a function that fetches products from an API.
const getData = async () => {
let res = await axios.get("https://fakestoreapi.com/products");
setApiData(res.data);
};
My first instinct was simple.
Just call it inside the component.
function App() {
getData();
return <h1>Hello React</h1>;
}
Looks harmless...
Right?
Not really.
Here's what actually happens.
Component Renders
β
getData() Runs
β
setApiData()
β
State Updates
β
Component Renders Again
β
getData() Runs Again
β
...
React isn't doing anything wrong here.
Every time the state changes...
React renders again.
Since getData() is inside the component, it runs again too.
Which updates the state.
Which causes another render.
Which calls getData() again.
And the cycle never ends.
That was the moment I realized:
React doesn't know that I only wanted to fetch the data once.
I have to tell it.
useEffect()
That's where today's star finally entered the picture.
useEffect(() => {
getData();
}, []);
At first, this syntax looked strange.
Especially that empty array at the end.
What exactly is it doing?
Turns out...
That tiny array controls when the effect should run.
useEffect
Here's the exact code I used today.
useEffect(() => {
getData();
}, []);
This tells React:
"After the component renders for the first time, run
getData()."
The important part is the empty dependency array.
[]
It means:
Run this effect only once after the initial render.
Now the flow looks much cleaner.
Component Renders
β
useEffect Runs
β
API Request
β
State Updates
β
Component Re-renders
β
Effect Doesn't Run Again β
That single change completely solved the problem.
Today's lesson also introduced me to Axios.
Before using it, I had to install it.
npm install axios
Then importing it was straightforward.
import axios from "axios";
Fetching data looked like this.
const getData = async () => {
const res = await axios.get("https://fakestoreapi.com/products");
setApiData(res.data);
};
This was my first time using Axios instead of the built-in fetch() API.
One thing I immediately noticed was how simple the response felt.
With Axios, the actual data is already available inside:
res.data
So after fetching the products, I simply updated my state.
setApiData(res.data);
React re-rendered the component, and the products became available to display.
That felt much cleaner than I expected.
If I'm being honest...
The dependency array confused me more than useEffect() itself.
I kept wondering,
"Why is React asking me for an array?"
Eventually, I realized that the dependency array is simply React's way of knowing when an effect should run again.
There are three common patterns.
useEffect(() => {
console.log("Running...");
});
This runs after every render.
Render
β
Effect
Render
β
Effect
Render
β
Effect
useEffect(() => {
console.log("Running...");
}, []);
This runs only once.
First Render
β
Effect Runs β
Next Render
β
Skipped
useEffect(() => {
console.log("Count changed");
}, [count]);
Now React watches count.
If count changes...
the effect runs again.
If it doesn't...
React skips it.
After seeing all three together, I stopped memorizing them and started thinking about what React was actually doing.
| Dependency Array | When it Runs |
|---|---|
| No array | After every render |
[] |
Only after the first render |
[count] |
After the first render and whenever count changes |
That tiny table made the dependency array much easier to remember.
I thought today's biggest lesson would be fetching data from an API.
Surprisingly, the thing that impressed me the most had nothing to do with APIs.
It was understanding why React needs a cleanup function.
At first, I didn't understand why React lets us return a function inside useEffect().
useEffect(() => {
console.log("About rendering...");
return () => {
console.log("Cleanup");
};
}, []);
Why would I return a function from another function?
It felt... unusual.
Then I tried a small experiment.
Inside my About component, I created an interval.
let interval = setInterval(() => {
console.log("Hey, I'm in About");
}, 1000);
Every second, the console printed:
Hey, I'm in About
Exactly as expected.
Then I switched from the About component to the Contact component.
Since the About component disappeared...
I expected the logging to stop.
It didn't.
The console kept printing:
Hey, I'm in About
Hey, I'm in About
Hey, I'm in About
...
That completely confused me.
The component wasn't even on the screen anymore.
So why was the interval still running?
This was probably the biggest realization of today's lesson.
When React removes a component from the screen...
it only removes the component itself.
It doesn't automatically stop timers, intervals, or event listeners created by JavaScript.
Those things continue running unless I stop them myself.
That's exactly why the cleanup function exists.
Here's the version that fixed everything.
useEffect(() => {
let interval = setInterval(() => {
console.log("Hey, I'm in About");
}, 1000);
return () => {
clearInterval(interval);
};
}, []);
Here's how I visualize it now:
About Component Mounts
β
Interval Starts
β
User Switches Page
β
Component Unmounts
β
Cleanup Function Runs
β
Interval Stops β
That finally made the purpose of cleanup click for me.
React isn't cleaning things automatically.
It's simply giving me one last chance to clean up anything my component created before it disappears.
Another thing I kept hearing today was:
At first, they sounded like complicated React terms.
But after today's examples, I started thinking about them much more simply.
Mount
β
Component appears for the first time.
Re-render
β
Component runs again because state or props changed.
Unmount
β
Component is removed from the screen.
That also explained why the cleanup function runs during unmounting.
React is basically saying:
"Your component is leaving. If you started anything, now is the time to stop it."
This is how I picture useEffect() now.
Component Renders
β
React Updates the UI
β
useEffect Runs
β
Side Effect Happens
(API Call, Timer, Event Listener...)
And if the component is removed...
Component Unmounts
β
Cleanup Function Runs
β
Resources Are Released
Thinking about it this way made today's lesson much easier to remember.
useEffect() lets React run code after rendering.useEffect().[]) runs the effect only once after the initial render.I'm currently learning React through React Cohort 3.0 by Devendra Dhote at Sheriyans Coding School.
This article is based on my own class notes, code experiments, and understanding. Writing these posts helps me reinforce what I've learned, and hopefully makes things a little easier for other beginners too.
If I've misunderstood something, I'd genuinely appreciate any corrections in the comments. π
Today's lesson completely changed how I think about React.
Before today's class, I thought useEffect() was mostly for fetching data from APIs.
By the end of the lesson, I realized API calls are just one example of a side effect.
The real purpose of useEffect() is much bigger.
It's React's way of letting us run code after rendering, while also giving us a chance to clean everything up when a component disappears.
The cleanup function was my favorite part of today's lesson.
Watching an interval continue running after a component disappeared was confusing at first, but once I understood why cleanup exists, everything finally clicked.
I'm starting to notice something interesting about React.
Every hook I've learned so far exists because it solves a very specific problem.
The more I understand those problems, the more React itself starts making sense.
See you on Day 13! π
π¬ What confused you the most when you first learned useEffect()? Was it the dependency array, the cleanup function, or simply knowing when to use it? I'd love to hear your experience in the comments. π
If you're following along with this series, you can also find me on GitHub, where I'll be sharing my projects and documenting my progress.
π€ AI Disclosure: This article is based on my own React learning journey, class notes, code experiments, and understanding. I used ChatGPT to help improve the writing, structure, and readability of this post. I reviewed and verified the technical explanations before publishing, and I take responsibility for everything shared here.
Thanks for reading! π