Memoize or Defer?Exploring the Performance Benefits of useMemo and Suspense in React

As we know, React is a popular JavaScript library used for building user interfaces. It provides several features and utilities that make it easier to build complex applications. Two such features are useMemo and Suspense. While both of these features can improve the performance of your React application, they have different use cases and implementation details.

useMemo

useMemo is a hook (function) that allows you to memoize a function result so that the function is only re-rendered when its dependencies have changed. It is very useful for optimizing performance especially when we are doing expensive operations.useMemo is often used to optimize the rendering of components by preventing expensive operations from being repeated unnecessarily.

For example, suppose we have a component that needs to render some data based on its props. We could use useMemo to memoize the result of that calculation so that it will only be re-rendered when the relevant props change.

Here is an example:

const MyMemo = ({ data }) => {
  const data = useMemo(() => {
    // Performing some expensive computation based on data
    return ...
  }, [data]);
  return (
    <div>{data}</div>
  )
}
export default MyMemo;

In the above example, the useMemo hook takes two arguments: a function that performs the heavy computations and an array of dependencies. If any of the dependencies change the function will be re-rendered and its result will be memoized i.e. returning the cached result when the same data/state/props are provided.

Suspense

Suspense is a component that allows you to suspend rendering while some asynchronous operation is in progress such as a network request. This can be useful for improving the user experience by showing a loading indicator/Shimmer UI instead of a blank screen.

Here is an example:

import { useState, useEffect } from 'react';

const MySuspense = () => {
  const [data, setData] = useState(null);
  useEffect(() => {
      fetchData();
  }, []);
  async function fetchData() {
     const response = await fetch('mydata.com/data');
     const json = await response.json();
     setData(json);
 }
  return (
    <div>{data}</div>
  )
}

export default MySuspense;

In the above example, the useEffect hook fetches some data from a server when the component is mounted. If the request takes a long time to complete until then the blank screen will be showing. To improve this user experience we could use Suspense to show a loading indicator / Shimmer UI instead of blank screen.

const MyComp = () => {
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <MySuspense />
    </Suspense>
  )
}
const MySuspense = () => {
  const [data, setData] = useState(null);
  useEffect(() => {
      fetchData();
  }, []);
  async function fetchData() {
     const response = await fetch('mydata.com/data');
     const json = await response.json();
     setData(json);
 }
  return (
    <div>{data}</div>
  )
}
export default MyComp;

In the above example, the Suspense component wraps the MySuspense component. If the API request takes a long time to complete the fallback prop will be passed to Suspense and it will be rendered until the request is completed.

Conclusion

In summary, useMemo is a hook for memoizing the result of a function, while Suspense is used to handle the loading state of components that require some asynchronous data or components to be loaded. Both can be useful for optimizing performance and creating great user experiences in your React applications.