As a React developer, it’s critical to increase the performance of your React applications to provide a smooth and streamlined user experience. This post will cover the best practices for writing code in React JS.
1. Minimize Re-renders and Use Memoization
Memoization is a technique for minimizing expensive computations or function calls by caching their results. It allows you to avoid recalculating expensive computations or re-executing costly function calls, hence boosting the overall efficiency of your React application.
In functional components, we can use memo or useCallback to optimize rendering performance.
Example
import { memo } from 'react'; const HighCalculativeComponent = memo(({ data }) => { // Expensive computation or function call here return <div>{data}</div>; });
import { useCallback } from "react"; const addTodo = useCallback(() => { /*Logic here*/ },[todos]); return ( <> <Todos todos={todos} addTodo={addTodo} /> <hr /> <div> <Component1> <Component2> </div> </> );
2. Avoid Using Index as Key
When rendering lists in React, avoid using the array’s index as the key property. Using the index as the key can cause unexpected behavior and poor performance when adding, removing, or reordering items in a list. Instead, utilize your data’s unique identification as the key.
Example
const ListComponent = () => { const items = [ { id: 1, title: "Item 1" }, { id: 2, title: "Item 2" }, { id: 3, title: "Item 3" } ]; return ( <ul> {items.map(item => ( <li key={item.id}>{item.title}</li> ))} </ul> ); };
3. Use Functional Components
Functional components have a reduced memory footprint and are faster to render than class components. They also encourage improved code organization and reusability. As a good practice, try to use functional components whenever possible for better performance and maintainability.
Example
const TestComponent = ({ data }) => { return <div>{data}</div>; };
4. Use React.Fragment
React.Fragment is a better option than wrapping many elements in an extra div element when presenting them without the requirement for a separate container element. Reducing the number of DOM nodes through the use of React.Fragment improves rendering efficiency.
Example
<React.Fragment> <div>Element 1</div> <div>Element 2</div> <div>Element 3</div> <div>Element 4</div> </React.Fragment>
5. Reduce Unnecessary Props
To reduce unnecessary re-renders, only pass your components the props that are actually needed. When you only need a small number of properties from an object, do not provide huge or constantly changing objects as props. You can get better results from your React components by cutting down on needless properties.
Example
const TestComponent = ({ name }) => { return <div>{name}</div>; };
6. Batch State Updates
Use React batch updates to maximize efficiency when changing component state. Multiple state updates can result in needless renderings, which can be avoided by encapsulating them in a single function call or by utilizing the useEffect hook.
Example
const TestComponent = () => { const [count, setCount] = useState(0); const handleClick = () => { setCount(count + 1); // Not ideal, causes unnecessary re-render setCount(count + 1); // Not ideal, causes unnecessary re-render // Ideal usage, only triggers a single re-render setCount((prevCount) => prevCount + 2); }; return ( <div> <p>Count: {count}</p> <button onClick={handleClick}>Increment Count</button> </div> ); };
7. Avoid Inline Functions
When sending function instances as props, especially, try to avoid creating new instances of them inside your render methods. Because inline functions generate distinct references for every render, they may result in needless re-renders. To prevent needless re-renders, define functions outside of the render method and pass them as stable references instead.
Example
const MyComponent = ({ onClick }) => { const handleClick = useCallback(() => { onClick(); }, [onClick]); return <button onClick={handleClick}>Click Me</button>; };
8. Use Code Splitting and Lazy Loading
Divide your React application into manageable segments with code splitting and load only the necessary sections as needed. By loading components or routes asynchronously, you can decrease the overall bundle size and speed up the initial load time.
Example
const LazyComponent = React.lazy(() => import('./LazyComponent')); const MyComponent = () => { return ( <React.Suspense fallback={<div>Loading...</div>}> <LazyComponent /> </React.Suspense> ); };
9. Optimize Network Requests
Enhance efficiency by reducing the number of network queries your React application sends out. Combine queries using batching or pagination into a single request and utilize compression and caching to save server load and improve response times.
10. Use Virtualization to Handle Large Lists
Implement virtualization techniques like windowing or infinite scrolling for rendering long lists in React. Virtualization improves rendering efficiency and reduces memory usage by rendering only the items that are visible.
11. Minify and Cache Static Files
Optimize website performance by compressing and caching static assets such as CSS, images, and JavaScript files. Deliver static assets efficiently to provide users with a faster experience.
12. Defer Expensive Operations in useEffect
Use the useEffect hook to defer expensive operations that don’t need to be synchronous to the next rendering frame. By delaying expensive operations, you may avoid blocking the main thread and increase the overall responsiveness of your React application.
Example
const LazyComponent = React.lazy(() => import('./LazyComponent')); const MyComponent = () => { return ( <React.Suspense fallback={<div>Loading...</div>}> <LazyComponent /> </React.Suspense> ); };
Conclusion
Implementing these best practices guarantees that your components re-render only when needed, resulting in a more seamless user experience & dramatically improving the performance of your React applications.