Logo

dev-resources.site

for different kinds of informations.

Optimizing React Performance: Avoiding Unnecessary Re-renders

Published at
12/19/2024
Categories
react
webperf
avoidrerenders
abhay
Author
abhay_yt_52a8e72b213be229
Author
25 person written this
abhay_yt_52a8e72b213be229
open
Optimizing React Performance: Avoiding Unnecessary Re-renders

Avoiding Re-renders in React

Avoiding unnecessary re-renders in React is essential for optimizing application performance. React's reconciliation process identifies changes in the component tree and updates only the necessary parts. However, improper state management, props passing, or component structure can lead to redundant re-renders.


Techniques to Avoid Unnecessary Re-renders

  1. Use React.memo React.memo prevents re-renders of functional components if their props haven’t changed.
   import React from "react";

   const Child = React.memo(({ name }) => {
     console.log("Child rendered");
     return <div>Hello, {name}</div>;
   });

   function Parent() {
     const [count, setCount] = React.useState(0);

     return (
       <div>
         <button onClick={() => setCount(count + 1)}>Increment</button>
         <Child name="React" />
       </div>
     );
   }

   export default Parent;
Enter fullscreen mode Exit fullscreen mode
  • Without React.memo, Child would re-render every time the parent renders, even if name remains unchanged.
  • React.memo ensures Child renders only when its name prop changes.

  1. Use useCallback for Functions React re-creates functions on every render, which may trigger re-renders if passed as props. Use useCallback to memoize functions.
   import React, { useState, useCallback } from "react";

   const Child = React.memo(({ onClick }) => {
     console.log("Child rendered");
     return <button onClick={onClick}>Click Me</button>;
   });

   function Parent() {
     const [count, setCount] = useState(0);

     const handleClick = useCallback(() => {
       console.log("Button clicked");
     }, []);

     return (
       <div>
         <button onClick={() => setCount(count + 1)}>Increment</button>
         <Child onClick={handleClick} />
       </div>
     );
   }

   export default Parent;
Enter fullscreen mode Exit fullscreen mode
  • Without useCallback, handleClick would be recreated on every render, causing Child to re-render.
  • useCallback memoizes handleClick, preventing unnecessary updates.

  1. Use useMemo for Expensive Calculations Use useMemo to memoize computed values and avoid re-calculations on every render.
   import React, { useState, useMemo } from "react";

   function Parent() {
     const [count, setCount] = useState(0);
     const [other, setOther] = useState(0);

     const expensiveCalculation = useMemo(() => {
       console.log("Expensive calculation");
       return count * 2;
     }, [count]);

     return (
       <div>
         <div>Result: {expensiveCalculation}</div>
         <button onClick={() => setCount(count + 1)}>Increment Count</button>
         <button onClick={() => setOther(other + 1)}>Increment Other</button>
       </div>
     );
   }

   export default Parent;
Enter fullscreen mode Exit fullscreen mode
  • useMemo ensures the expensive calculation is re-computed only when count changes.

  1. Avoid Inline Functions and Objects as Props Inline functions and objects are recreated on every render and can trigger re-renders.

Problematic Example:

   const Child = React.memo(({ config }) => {
     console.log("Child rendered");
     return <div>Config: {JSON.stringify(config)}</div>;
   });

   function Parent() {
     const config = { color: "blue" }; // Re-created on every render

     return <Child config={config} />;
   }
Enter fullscreen mode Exit fullscreen mode

Solution: Use useMemo for Objects:

   function Parent() {
     const config = React.useMemo(() => ({ color: "blue" }), []);

     return <Child config={config} />;
   }
Enter fullscreen mode Exit fullscreen mode

  1. Split Components into Smaller Pieces Break large components into smaller, reusable pieces. This limits the scope of updates.
   const Counter = React.memo(({ count }) => {
     console.log("Counter rendered");
     return <div>Count: {count}</div>;
   });

   function App() {
     const [count, setCount] = useState(0);
     const [name, setName] = useState("");

     return (
       <div>
         <Counter count={count} />
         <input
           value={name}
           onChange={(e) => setName(e.target.value)}
           placeholder="Enter name"
         />
         <button onClick={() => setCount(count + 1)}>Increment</button>
       </div>
     );
   }
Enter fullscreen mode Exit fullscreen mode
  • Only Counter will re-render when count changes, not the input field.

  1. Avoid Re-rendering with Context API Context updates trigger re-renders for all consuming components. Use selective context or libraries like zustand or React Query.

Using Selector:

   const CounterContext = React.createContext();

   function CounterProvider({ children }) {
     const [count, setCount] = useState(0);
     return (
       <CounterContext.Provider value={{ count, setCount }}>
         {children}
       </CounterContext.Provider>
     );
   }

   function DisplayCount() {
     const { count } = React.useContext(CounterContext);
     console.log("DisplayCount rendered");
     return <div>Count: {count}</div>;
   }

   function IncrementButton() {
     const { setCount } = React.useContext(CounterContext);
     console.log("IncrementButton rendered");
     return <button onClick={() => setCount((c) => c + 1)}>Increment</button>;
   }

   function App() {
     return (
       <CounterProvider>
         <DisplayCount />
         <IncrementButton />
       </CounterProvider>
     );
   }
Enter fullscreen mode Exit fullscreen mode
  • Here, DisplayCount and IncrementButton render independently.

  1. Avoid Updating Parent State from Child Updating parent state from a child can force the parent and all its children to re-render. Pass handlers sparingly.

  1. Optimize Lists with Keys React needs unique keys for list items to avoid unnecessary re-renders.
   const List = ({ items }) => {
     return (
       <ul>
         {items.map((item) => (
           <li key={item.id}>{item.name}</li>
         ))}
       </ul>
     );
   };
Enter fullscreen mode Exit fullscreen mode

Ensure key is unique and stable.


Tools to Detect Re-renders

  1. React Developer Tools: Inspect which components re-rendered.
  2. why-did-you-render Library: Logs unnecessary re-renders.

Conclusion

Avoiding unnecessary re-renders improves application performance, reduces rendering overhead, and enhances user experience. By understanding React’s rendering behavior and using tools like React.memo, useMemo, and useCallback, you can optimize your components effectively.

webperf Article's
30 articles in total
Favicon
Redefining Web Performance Standards with INP
Favicon
How to avoid frontend tech making us resentful
Favicon
Understanding PHP-FPM: Key Differences from Traditional PHP Processes and Benefits
Favicon
How Mentimeter deliver reliable live experiences at scale
Favicon
The Art of Prefetching and Preloading: Enhancing Web Performance
Favicon
The curious case of the paragraph with the bad CLS
Favicon
JavaScript Frameworks - Heading into 2025
Favicon
Technical SEO for Developers: Mastering Site Structure and Performance
Favicon
Extending Lighthouse for custom image and video optimization analysis
Favicon
Assassin ⚡️ - An open source, free database for killing slow webpages
Favicon
A Comprehensive Guide to Web Vitals: Metrics That Matter for Performance
Favicon
Why should you care about website performance?
Favicon
Screener.in Search API: A Performance Checkup! 🔎
Favicon
How Sportsbet handles 4.5M daily chat messages on its 'Bet With Mates' platform
Favicon
Enhancing React Performance with Concurrent Rendering
Favicon
Optimizing React Performance: Avoiding Unnecessary Re-renders
Favicon
Master React Profiler: Optimize Your App's Performance
Favicon
Lightweight, Transparent, Animated: Get All of Them by WebP Format
Favicon
Prerender Pages in Browser For Faster Page Load
Favicon
How we optimized perceived performance to improve our KPIs: a Hotjar case study
Favicon
Sites speed optimisation is a destination, not a journey
Favicon
How to Build a High-Performance WordPress Website: A Developer’s Guide
Favicon
Performance Optimization in React
Favicon
Subsequent Page Load Optimization 🚀
Favicon
How to Build Blazing Fast Websites with Any Framework
Favicon
Everything to know about Mobile App Performance Test Tools, Metrics, & Techniques
Favicon
Efficient State Management in Next.js: Best Practices for Scalable Applications
Favicon
Top 5 Tips to Supercharge Your Express.js App for Lightning-Fast Performance
Favicon
A useState performance tip you may not have known
Favicon
🚀 V8 Engine Secrets How We Slashed Memory Usage by 66% with TypedArrays

Featured ones: