skip to Main Content

I’m working on a React application, and I have a component that renders a list of items. I’ve noticed that as the list grows, the component’s performance degrades. Here’s the code for the component

import React, { useState, useEffect } from 'react';

const ItemList = ({ items }) => {
  const [filteredItems, setFilteredItems] = useState([]);

  useEffect(() => {
    // Expensive filtering operation
    const filterItems = () => {
      return items.filter(item => item.isActive);
    };
    setFilteredItems(filterItems());
  }, [items]);

  return (
    <div>
      {filteredItems.map(item => (
        <div key={item.id}>{item.name}</div>
      ))}
    </div>
  );
};

export default ItemList;

**
Are there any performance improvements that can be made to this component?
Is there a better way to handle filtering or rendering large lists in React?
I’ve already tried using React.memo and useCallback, but the performance issues persist. Any suggestions or best practices would be greatly appreciated!**

3

Answers


  1. useMemo() and useCallback() can prevent re-creation of functions or re-calculation of certain values/ state on every render, it doesn’t solve the issue of two many things being rendered. To solve this problem you basically have two options:

    1. Pagination
    2. Virtualization

    Pagination

    Instead of showing a list of all items you just show different pages with a fixed size of items like 10, 20, 30 as is e.g. the case on Google or Amazon search results. This is usually the most straightforward implementation without a need for a 3rd party library.

    Virtualization

    Here the idea is, that a user can only every see a certain subset of your list, therefore it is sufficient to only render what the user sees (and a bit of padding to top and bottom to allow for seemless scrolling). As the user scrolls and other items come into view those will be rendered lazily as required.

    Usually you do this using some library like react-virtualize or TanStack Virtual. Many component libraries also come with a component <Virtualized /> which does that for you so you can use that to virtualize lists.

    Virtualization typically comes with some constraints like that the rows should all have the same fixed height. There are some ways around that as well, but they can then again cause some performance issues.

    Login or Signup to reply.
  2. The new React docs now do a better job of highlighting and explaining common use cases like this. If you have the time, please take a look and read through the useEffect and useMemo docs because they highlight some scenarios like this, namely Why You Might Not Need An Effect

    1. To begin with, you should avoid setting state based on props. Because useEffects run after the render (return), that means that your large list will get rendered once, and then it will rerender again after the useEffect runs and sets the state to the new list. To avoid this, you should either filter the list directly or wrap it in a useMemo. Both of these run during the render, before the return.
    // if items are small or filter is not expensive
    const filteredItems = filterItems(props.items);
    
    // if items are large or filter is expensive
    const filteredItems = useMemo(() => filterItems(items), [props.items);
    
    1. Make sure the items array you’re passing as a prop has a stable reference or is properly memoized and is not returning a new array reference every time, otherwise useMemo and useEffect are pointless.

    2. As @Mushroomator pointed out in his answer, rendering large lists in react can lead to potential slow downs. You can even start noticing potential performance issues with 1000 simple divs, let alone divs with images, css animations and transitions (the devil in large lists)…

    My go to for virtualization is React-Virtuoso because it’s the simplest to use and doesn’t require for you to provide any heights/widths ahead of time. It just works. If you do know the heights ahead of time, it helps boost performance even more.

    Login or Signup to reply.
  3. import React, { useState, useEffect } from 'react';
    
    const ItemList = ({ items }) => {
      const [filteredItems, setFilteredItems] = useState([]);
    
      useEffect(() => {
        // Expensive filtering operation
        const filterItems = () => {
          return items.filter(item => item.isActive);
        };
        setFilteredItems(filterItems());
      }, [items]);
    
      return (
        <div>
          {filteredItems.map(item => (
            <div key={item.id}>{item.name}</div>
          ))}
        </div>
      );
    };
    
    export default 
    

    ItemList; this is alredy have best performance

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search