How do I optimize my caching in React? Detailed guide

React Optimized Cache Instance Tutorial

As one of the most popular front-end libraries for creating high-performance web applications, React follows a component-based approach, where each component has its own state and logic.

How to optimize caching in React? The biggest challenge for React is avoiding unnecessary rendering, which can lead to serious performance issues, especially in large applications. In this article, we’ll look at a few different ways to optimize the performance of your React application with different caching methods.

React’s approach to optimizing caching: React Hooks for memorization

Memoization is a feature provided by React itself. As we know, React creates a new reference every time it is re-rendered. If your component has a lot of computations, it will be computed every time it is re-rendered, even if the output doesn’t change.

To minimize CPU load by avoiding unnecessary load, React provides two hooks that help with memorization. Hooks follow a process where the result is cached in memory and when we get the same input, it is returned without recalculation. In the case of different inputs, the cache is invalidated.

useMemo()

React Optimized Cache Instance Tutorial: is a React-provided Hook for memorization that helps keep the cached value the same as the value provided to it. It tracks the input and returns the results of the previous execution.useMemo()

Let’s look at an example. Let’s say we have to add two huge numbers to a component that has:

const addTwoHugeNumbers=(a,b)=>{
return a+b
}

The functions written above are heavy on the CPU, so they should only be calculated when the value of and changes. However, by default, it will run on every re-render.ab

With us, we can store the result of a specific value, which means that the function will not be calculated, and we will directly get the result of the previous calculation:useMemo()

const memoizedValue = useMemo(() => addTwoHugeNumbers(a, b), [a, b])

The value is stored in the . We’ve passed the dependency array to, and it tells it when to run again. In our case, it will run when any value changes.memoizedValueuseMemo

UseCallback()

With useCallback() we also gain the ability to remember, but it works differently. useCallback() does not remember the value, but rather the callback function provided to it. Let’s look at a small example:

const increment = (() => {
  setCount(count + 1);
});

using, the above function looks like the following code:useCallback()

const increment = useCallback(() => {
  setCount(count + 1);
}, [count]);

useCallback()The delta function will be remembered and will only run when a given dependency changes. It doesn’t keep track of the value returned by the input or function.

Lazy loading of React components

How to optimize caching in React? Lazy loading in React renders the necessary components upfront and delays loading unimportant components until later.

Especially in larger applications, this approach is highly recommended to improve performance. In React, we have built-in options to lazy load components.

We’ve created a component called and we want it to lazy load, and we can do this:</Artists>

import { lazy } from 'react';

First, we import lazy from React and use it like this:

const Artists = React.lazy(() => import('./Artists'));

function App() {
  return (
    <div>
      <Artists />
    </div>
  );
}

useRef()

React’s approach to optimizing caching: we know that whenever it’s used in a component, it re-renders in the component when the state changes. In order to track state without causing re-rendering, React introduced hooks.useState()useRef()

In some cases, it may not be the right solution for your application. Ideal for situations where the state we need doesn’t result in a re-rendering and doesn’t contribute to the visible information rendered by the component. For example, you can use it to count renders:useState()useRef()

function App() {
    const [foo, setFoo] = React.useState(false)
    const counter = React.useRef(0)
    console.log(counter.current++)
    return (
      <button onClick={() => setFoo(f => !f)} > Click </button>
     )
}

ReactDOM.render(<React.StrictMode><App /></React.StrictMode>, document.getElementById('mydiv'))

In the code above, we have a simple switcher for rerendering the component. Counter is a variable ref that persists its value. We could do the same with useState(), but it would result in two renders for each toggle.

React Optimized Cache Instance Tutorial: Redux Cache Selector

A selector is simply a function that is used to select data from a larger pool of data. In React, selectors are widely used to get values from Redux storage. Selectors are very useful and powerful, but they also have their own drawbacks.

In React Redux, we have hooks for getting status from the store. The problem is that it runs every time the component is rendered. In some cases it may be ideal, but most of the time, the data returned by the selector does not change, which makes the calculation unnecessary.useSelector()useSelector()useSelector()

Let’s look at an example:

import React, {useEffect,useState} from 'react'
import {useSelector, useDispatch} from 'react-redux'
import {getPosts} from './postActions'

export const List=()=>{
  Const [toggle, setToggle]=useState(false)
  const myPosts=useSelector(state=>state.posts)
  const dispatch=useDispatch()


  return(
    <div>
    {myPosts.map(post=><p>{posts}<p/>)}
    <button type="button" onClick={()=>{setToggle(!toggle)}} >Click Me!</button>
    <div/>
  )
}

In the code above, we’re changing the toggle state, and the component renders every time we do this. The hook will also run even if the post doesn’t match our Ultimate Edition in-store change.useSelector()

To solve this problem, we will cache the result of a selector function. Although there is no built-in React solution, we have a number of third-party libraries that allow us to create cache selectors. Let’s use Reselect, which is a well-known solution for cache selectors.

Reselect

React’s approach to optimizing caching: Reselect is a popular library for creating memory selectors. You can install it into your project using the following command:

yarn add reselect

We can use Reselect as follows:

import { createSelector } from 'reselect' 
import React, {useEffect,useState} from 'react'
import {useSelector, useDispatch} from 'react-redux'
import {getPosts} from './postActions'

export const List=()=>{
  Const [toggle, setToggle]=useState(false)
  const myPosts = createSelector(state=>state.posts)
  const dispatch=useDispatch()


  return(
  <div>
  {myPosts.map(post=><p>{posts}<p/>)}
  <button type="button" onClick={()=>{setToggle(!toggle)}} >Click Me!</button>
  <div/>
  )
}

In the code above, we’re importing from Reselect, which takes a selector and returns a memory version of it. With the memorized version, the component does not calculate the value of the selector, even after thousands of re-renders, unless the value changes. Reselect has proven to be an excellent solution to large application performance issues.createSelectorpostReducercreateSelector

Optimize API calls with React Query

How to optimize caching in React? React handles asynchronous operations in its own way, which is sometimes a problem for developers. A common pattern for asynchronous operations is to fetch server data in a Hook, which runs on every render and fetches new data every time, even if there is no new data on the server.useEffect

React Query, on the other hand, caches the data and returns it before making a call, but if the server returns new data that is the same as the previous data, React Query will not re-render the component. We can use React Query as follows:

import React from 'react'
import {useQuery} from 'react-query'
import axios from 'axios'

async function fetchPosts(){
    const {data} = await axios.get('https://jsonplaceholder.typicode.com/posts')    
    return data
}

function Posts(){
    const {data, error, isError, isLoading } = useQuery('posts', fetchPosts) 
    // first argument is a string to cache and track the query result
    if(isLoading){
        return <div>Loading...</div>
    }
    if(isError){
        return <div>Error! {error.message}</div>
    }

    return(
        <div className='container'>
        <h1>Posts</h1>
        {
            data.map((post, index) => {
                return <li key={index}>{post.title}</li>
            })
        }

        </div>
    )
}

export default Posts

React snippet

React Optimized Cache Instances Tutorial: If you’re a React developer, you’ve probably encountered an error that says wrap a component with a parent div. If you don’t need an extra div in your component, it doesn’t make sense to add it. For example, if you have 1000 components in your React application, then you will have 1000 additional divs, which can be heavy on the DOM. To avoid this, React gives you the option to use snippets:

const Message = () => {
  return (
    <React.Fragment>
      <p>Hello<p/>
      <p>I have message for you<p/>
    </React.Fragment>
  );
};

The following code snippet is exactly the same as the code above, used as a shortcut:<>React.Fragment

const Message = () => {
  return (
    <>
      <p>Hello<p/>
      <p>I have message for you<p/>
    </>
  );
};

Either way, you can avoid adding extras, which reduces DOM markup, improves rendering performance, and reduces memory overhead.<div>

React virtual lists

How to optimize caching in React? Often, we need to render large lists on the browser; Doing so is complicated for the browser because it has to create new nodes and draw them all on the screen.

To make the process in React efficient, we can choose to use virtual lists. The virtual list renders only a handful of items as needed, simply replacing them as the user scrolls through the items dynamically.

Rendering is faster than changing the DOM, so you can use virtual lists to render thousands of list items with fast performance. React-virtualized is an excellent library with components that render virtual lists.

React’s approach to optimizing caching: Functional components

React started with class-based components, however, due to its lightweight nature, functional components are now recommended. Functional components are basically functions that are faster to create, and they are easier to minify, reducing the size of the package.

React Optimization Cache Instance Tutorial Conclusion

In this tutorial, we’ve covered several different solutions for optimizing cache management in React applications, such as memory, cache selectors, lazy loading, React fragments, virtual lists, and functional components. Each of these approaches can improve your application by reducing the number of unnecessary component renders, reducing overhead, and increasing speed.

The right solution will depend on the needs of your individual project, but hopefully this article has helped you understand the options available.