오늘은 리액트에서 컴포넌트의 성능을 최적화 하는데 사용하는 훅인 useMemo에 대해서 기록해보려한다.
1. useMemo
useMemo는 컴포넌트의 성능을 최적화시킬 수 있는 대표적인 리액트 훅 중 하나이다.
memo는 memoization으로 '메모리에 넣기'라는 의미이다. 동일한 값을 반환하는 함수를 반복적으로 호출해야 한다면 처음 수행했던 결과값을 메모리에 저장해두고, 동일한 입력이 들어오면 메모리에서 꺼내 재사용하는 것이다.
함수형 컴포넌트에서는 '컴포넌트 렌더링 -> 컴포넌트 함수 호출 -> 모든 내부 변수 초기화' 의 순서를 거치는데, 이 말은 컴포넌트가 렌더링 될 때마 변수들이 모두 초기화 되기 때문에 함수가 반복적으로 호출이 된다는 의미이다.
예를들어 아래와 같은 코드에서 렌더링 될 때마다 value라는 변수가 초기화되고, calculate 함수가 불필요하게 호출된다.
function Component() {
const value = calculate();
return <div>{value}</div>
}
function calculate() {
return 10;
}
함수가 복잡해진다면 불필요한 호출이 효율성 측면에서 떨어지기 때문에 이런 경우 아래 코드와 같이 useMemo 훅을 사용한다.
const value = useMemo(() => {
return calculate();
}, [item])
// 첫 번째 인자 : 콜백 함수
// 두 번째 인자 : 의존성 배열
// 의존성 배열 안에 값이 있다면 값이 업데이트 될 때만 콜백함수를 호출하여 메모리에 저장된 값을 업데이트
// 의존성 배열이 빈 배열이라면 처음 마운트 될 때만 값을 계산하고, 이후 메모리에 저장된 값을 가져와 사용
처음 계산된 값을 메모리에 저장해 렌더링되어도 함수를 호출하지 않고, 메모리에 저장되어 있는 값을 사용해 컴포넌트의 성능을 최적화 하는것이다.
2. 예제
위 코드에서 useEffect의 의존성 배열에 background를 넣었지만, count의 상태값을 변경해도 useEffect가 호출되는 것을 확인할 수 있다. 자바스크립트에서 객체는 원시 타입과 다르게 값이 저장될 때 주소값으로 저장되기 때문이다.
그래서 count의 상태값이 바뀌면 컴포넌트가 재호출되면서 background의 주소값이 변경되어 useEffect가 호출되는 것이다.
이러한 불필요한 호출을 방지하기 위해 useMemo 훅을 사용하는 것이다. 위 코드에서 주석처리된 부분을 전과 비교해 확인해보면 차이를 확인할 수 있다.
(코드는 좌측바 드래그를 통해 확인)