Hey there, coders! 👋 I’m Vikas Sankhla, founder of the YouTube channel Web Codder, and today we’re going to chat about something super important:
👉 How to make your React app lightning-fast! ⚡
I like to think of this like tuning a car 🚗. React is powerful, but if we don’t keep it optimised, it can get sluggish and eat up too much fuel (aka resources).
🤔 Why Should You Care About Performance?
Imagine this:
- You click a button, but it takes 5 seconds to show results. 😤
- You scroll a page, but it’s lagging and freezing. ❄️
Not fun, right?
⚠️ Fact:
Slow apps = unhappy users = fewer visitors.
We want our apps to be smooth like butter 🧈. And guess what? React gives us tools to optimize performance easily!
🕵️ Understanding React’s Rendering Behavior
First things first: Let’s understand how React works under the hood.
React is like an artist 🎨.
Every time something changes in your app (like a click or typing), React:
- 🏗 Rebuilds a Virtual DOM tree.
- 🔎 Checks what actually changed.
- 🖼 Updates only the parts of the real DOM that need it.
This is usually fast… but sometimes, we do extra work we don’t need.
Example:
jsxCopyEditfunction Greeting({ name }) {
console.log("Rendering Greeting 😄");
return <h1>Hello, {name}!</h1>;
}
function App() {
const [count, setCount] = React.useState(0);
return (
<>
<Greeting name="Vikas" />
<button onClick={() => setCount(count + 1)}>Clicked {count} times</button>
</>
);
}
Now, even if you just click the button, React will re-render the Greeting
component 😮. But why? It didn’t change!
👉 This is where optimization starts.
🛠️ React’s Optimization Tools
Let’s look at the main tools React gives us:
Tool | What It Does |
---|---|
React.memo | 🧠 Memoizes a whole component to avoid unnecessary re-renders. |
useMemo | 🧮 Memoizes a calculation result. |
useCallback | 🔗 Memoizes a function, keeps the same reference. |
Code Splitting | ✂️ Splits your code to load only what’s needed. |
Lazy Loading | 💤 Loads parts of your app on demand. |
React Suspense | ⏳ Handles loading states nicely when using lazy loading. |
🧠 Using React.memo
Let’s go back to our Greeting example.
We can wrap it with React.memo
:
jsxCopyEditconst Greeting = React.memo(function Greeting({ name }) {
console.log("Rendering Greeting 😄");
return <h1>Hello, {name}!</h1>;
});
Now:
Even if we click the button 100 times, Greeting
won’t re-render unless name
changes. Cool, right? 😎
🔍 How React.memo
Works
Here’s the simple idea:
- It remembers the last props.
- If props haven’t changed 👉 it skips rendering.
🚦 When to use it:
✅ Use React.memo
for components that:
- Get the same props often.
- Are a bit heavy to render.
⚠️ Don’t overuse it! Wrapping everything in React.memo
can actually slow things down a bit because React has to compare props.
🧮 Using useMemo
Ever had a big calculation that runs every time your component re-renders? That’s wasteful. 😩
Example:
jsxCopyEditconst bigNumber = 123456789;
const expensiveCalculation = (num) => {
console.log("Calculating... 🧮");
for (let i = 0; i < 1000000000; i++) {}
return num * 2;
};
function App() {
const [count, setCount] = React.useState(0);
const result = expensiveCalculation(bigNumber);
return (
<>
<p>Result: {result}</p>
<button onClick={() => setCount(count + 1)}>Clicked {count} times</button>
</>
);
}
This calculates every time even if you just click the button.
💡 Solution: useMemo
jsxCopyEditconst result = React.useMemo(() => expensiveCalculation(bigNumber), [bigNumber]);
Now the calculation only runs if bigNumber
changes. 👌
🔗 Using useCallback
Sometimes you pass functions down to child components.
React sees a new function every time and might re-render the child.
Example:
jsxCopyEditfunction Button({ onClick }) {
console.log("Rendering Button 🖱️");
return <button onClick={onClick}>Click me</button>;
}
function App() {
const [count, setCount] = React.useState(0);
const handleClick = () => {
setCount(count + 1);
};
return <Button onClick={handleClick} />;
}
👀 Even though Button didn’t change, it re-renders every time.
💡 Fix with useCallback
:
jsxCopyEditconst handleClick = React.useCallback(() => {
setCount(count + 1);
}, [count]);
This keeps the same function reference until count
changes.
✂️ Code Splitting & Lazy Loading
Imagine if your app is a Netflix movie 🎥.
Do you download the whole Netflix library before watching? No way! You just stream what you need.
That’s the idea of code splitting.
🛠 Code Splitting Example
Instead of importing everything at once:
jsxCopyEditimport BigComponent from './BigComponent';
You can lazy load:
jsxCopyEditconst BigComponent = React.lazy(() => import('./BigComponent'));
Then wrap it with Suspense
:
jsxCopyEdit<Suspense fallback={<div>Loading... ⏳</div>}>
<BigComponent />
</Suspense>
Boom 💥!
Your app only loads BigComponent
when needed, keeping the first load super fast.
🚧 Table of Key Concepts
Concept | What It Solves |
---|---|
React.memo | Avoids unnecessary component re-renders. |
useMemo | Avoids unnecessary recalculations. |
useCallback | Avoids recreating the same function every render. |
Lazy Loading | Defers loading of heavy components. |
Code Splitting | Splits your app into smaller chunks. |
Suspense | Shows a fallback UI while loading components. |

🏁 Wrapping Up Part 1
Awesome job staying with me till here! 🎉
We’ve learned:
- Why React apps can slow down.
- Tools React gives us to optimize performance.
- Simple, real-world examples to make it all crystal clear.
👉 Subscribe & follow me for more awesome content:
Let’s keep building fast and awesome apps together! 💪