Using "useMemo" instead of "useEffect" for computations in React
June 7, 2023 - 2 min read
beginner
react
typescript
One of the most common patterns in a React codebase is taking some information, transforming it,
and displaying that information visually. In this post I will demonstrate a common pitfall when
structuring this type of code that a lot of newcomers to React make: Using
useEffect
to transform
data.In this example, we have an array of users, each with a first name and an active flag.
interface User { firstName: string; active: boolean; } const users: User[] = [ { firstName: 'Elvie', active: false, }, { firstName: 'Janelle', active: true, }, ];
In this React component we are going to take the array of users and filter out any inactive users
before displaying a list of all active users.
interface Props { users: User[]; } function ActiveUsers({ users }: Props) { const [activeUsers, setActiveUsers] = useState<User[]>([]); useEffect(() => { // filter out all users that are inactive const filteredUsers = users.filter((user) => user.active); setActiveUsers(filteredUsers); }, [users]); // render a list of active users return ( <div> {activeUsers.map((activeUser, index) => ( <div key={index}> <h1>{activeUser.firstName}</h1> </div> ))} </div> ); }
Using
useEffect
here is not appropriate because the transformation is not a side effect. It is also
inefficient, requiring an additional render to apply the effect before displaying the active users.Instead, use the
useMemo
hook to transform the data:interface Props { users: User[]; } function ActiveUsers({ users }: Props) { // use "useMemo" to save the calculation const activeUsers = useMemo( () => users.filter((user) => user.active), [users], ); // render a list of active users return ( <div> {activeUsers.map((activeUser, index) => ( <div key={index}> <h1>{activeUser.firstName}</h1> </div> ))} </div> ); }
The Official React documentation has a great page on avoiding effects, check it out.