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
useMemo()
anduseCallback()
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: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.
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
anduseMemo
docs because they highlight some scenarios like this, namely Why You Might Not Need An EffectuseEffect
s run after the render (return), that means that your large list will get rendered once, and then it will rerender again after theuseEffect
runs and sets the state to the new list. To avoid this, you should either filter the list directly or wrap it in auseMemo
. Both of these run during the render, before the return.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, otherwiseuseMemo
anduseEffect
are pointless.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.
ItemList; this is alredy have best performance