메모이제이션은 컴퓨터 프로그램이 동일한 계산을 반복해야 할 때, 이전에 계산한 값을 메모리에 저장함으로써 동일한 계산의 중복 수행을 줄이는 최적화 기능이다.
useMemo
는 리액트에서 컴포넌트의 성능을 최적화하는 데에 사용하는 훅이다.
함수형 컴포넌트는 함수다. 함수형 컴포넌트가 렌더링이 된다는 것은 그 함수가 호출된다는 것이고, 그때 함수 내부에 정의해 놓은 내부 변수가 초기화된다. 컴포넌트는 state와 props의 변화로 인해 수많은 렌더링을 거치는데, 이때 동일한 계산을 반복하는 함수가 내부에 있다면 이를 최적화하는 과정이 꼭 필요하다.
useMemo(()⇒{}, [deps])
첫 번째 인수: 콜백함수 (CalculateValue)
메모이제이션 해 줄 값을 계산해서 리턴해 주는 함수다. 즉, 이 콜백이 리턴하는 값이 바로 useMemo가 리턴하는 값이 된다. 이 리턴하는 값을 메모이제이션한다.
두 번째 인수: 의존성 배열(dependencies)
의존성 배열 안에 있는 값이 업데이트될 때에만 콜백 함수를 다시 호출하여 메모리에 저장된 값을 업데이트해 준다. 함수 내에서 참조하는 state, props가 있다면 의존성 배열에 추가해 주면 된다.
만약 빈 배열이 할당될 경우 useEffect와 마찬가지로 마운트 될 때에만 값을 계산하고, 그 이후론 계속 메모이제이션된 값만 꺼내와서 사용한다.
useMemo는 메모이제이션된 값을 다시 리턴하므로, 이 값을 다시 변수에 담아서 사용해 줄 수도 있다.
마찬가지로 useMemo를 사용할 때는 import {useMemo} from ‘react';
를 꼭 해 줘야 한다.
그런데 useMemo를 무분별하게 남용하면 오히려 성능 면에서 안 좋은 점이 생길 수도 있으니 꼭 필요한 때에만 적절히 사용하는 게 중요하다.
import React from "react";
import "./List.css";
import TodoItem from "./TodoItem";
import { useState, useMemo } from "react";
const List = ({ todos, onUpdate, onDelete }) => {
const [search, setSearch] = useState("");
const onChangeSearch = (e) => {
setSearch(e.target.value);
};
const getFilteredData = () => {
if (search === "") {
return todos;
}
return todos.filter((todo) =>
todo.content.toLowerCase().includes(search.toLowerCase())
);
};
const filteredTodos = getFilteredData();
const { totalCount, doneCount, notDoneCount } = useMemo(() => {
const totalCount = todos.length;
const doneCount = todos.filter((todo) => todo.isDone).length;
const notDoneCount = totalCount - doneCount;
return {
totalCount,
doneCount,
notDoneCount,
};
}, [todos]);
return (...)
};
export default List;
위 예시에서는 List 컴포넌트에서 리스트의 개수, 완료된 리스트의 개수, 완료되지 않은 리스트의 개수를 렌더링하는 함수를 작성해 보았다.
List 컴포넌트는 App 컴포넌트의 자식 컴포넌트로, App 컴포넌트가 리렌더 되면 List 컴포넌트도 리렌더링 된다. 또한 List 컴포넌트 자체도 계속 반복되어 호출되는 경우가 있을 수 있다. 근데 여기서 리렌더 될 때마다 리스트의 개수를 다시 계산할 필요는 없으니 이를 useMemo를 사용하여 작성했다. useMemo는 메모이제이션 된 값을 다시 리턴하므로, 이를 구조 분해 할당을 통해 받아서 사용하면 된다.
React.memo()
는 리액트 함수 컴포넌트 최적화를 돕는 고차원 함수다. 이를 사용하면, 컴포넌트가 동일한 props로 렌더링될 때 리렌더링을 방지할 수 있다. 즉, 불필요한 렌더링을 줄여 성능 향상에 도움이 될 수 있다.
React.memo()
는 오직 props가 변경됐는지 아닌지만 체크한다. 근데 부모 컴포넌트가 리렌더링될 때 자식 컴포넌트도 함께 리렌더링되는 문제가 생길 수 있다. 이때 사용하는 것이 React.memo()
다.