useMemo에서 'Memo'란, Memoization을 뜻한다.
동일한 값을 return하는 함수를 반복적으로 호출해야 한다면 맨 처음 값을 계산할 때 해당 값을 메모리에 저장해서 필요할 때마다 다시 계산하지 않고 메모리에서 꺼내 재사용하는 기법이다.
들어가기 전에 한 가지 알아둬야 할 것이 있다.
함수형 컴포넌트는 말 그대로 함수이다.
함수형 컴포넌트가 렌더링
된다는 것은 그 함수가 호출
된다는 것이고, 함수는 호출될 때마다 내부의 모든 변수들이 초기화
된다.
function Component () {
const value = calculate();
return <div>{value}</div>;
}
function calculate () {
return 10;
}
컴포넌트가 렌더링 될 때마다 value 변수가 초기화 되기 때문에 calculate 함수는 반복적으로 호출된다.
그런데 만약 calculate 함수가 무거운 일을 하는 함수라면 아주 비효율적일 것이다.
이때 useMemo를 사용해 memoization 해주면, 간단히 해결할 수 있다.
useMemo는 처음 계산된 결과값을 메모리에 저장해서 컴포넌트가 반복적으로 렌더링 되어도 calculate를 다시 호출하지 않고, 이전에 이미 계산된 결과값을 메모리에서 꺼내와 재사용할 수 있게 해준다.
const value = useMemo(() => {
return calculate();
}, [item])
useMemo는 두 개의 인자를 받는데, 첫 번째 인자는 콜백 함수
, 두 번째 인자로는 배열
을 받는다.
임의의 컴포넌트 내부 코드 중 일부를 가져왔다고 생각해보자.
// 예제 1
const [isKorea, setIsKorea] = useState(true);
const location = isKorea ? '한국' : '외국';
useEffect(() => {
console.log('useEffect 호출');
}, [location])
// 예제 2
const [isKorea, setIsKorea] = useState(true);
const location = {
country: isKorea ? '한국' : '외국',
};
useEffect(() => {
console.log('useEffect 호출');
}, [location])
예제 1과 예제 2는 location의 값이 변할 때마다 컴포넌트의 렌더링이 발생한다는 점에서는 동일하다.
그러나 예제 1은 location이 아닌 다른 값 변화에 의한 렌더링 시 useEffect가 실행되지 않는 반면, 예제 2는 location이 아닌 다른 값 변화에 의한 렌더링에도 useEffect가 실행된다.
이 차이는 location 변수에 할당된 값의 타입이 다르다
는 점에서 발생한다.
객체 타입의 변수는 리렌더링 시 객체 자체를 재할당 받으므로 변수가 가리키는 주소값이 변하기 때문에 location이 바뀐다고 인식되므로 useEffect가 계속 실행되는 것이다.
이럴 경우 useMemo를 사용해 컴포넌트 최적화를 해주면 좋겠지!
// 예제 2에 useMemo 적용
const location = useMemo(() => {
return {
country: isKorea ? '한국' : '외국',
}
}, [isKorea])
useMemo를 사용한다는 것은 값을 재활용하기 위해 따로 메모리를 소비해서 저장한다는 것이므로 불필요한 값까지 모두 memoization 해버리면 오히려 성능이 악화될 수 있으므로 필요할 때만 적절히 사용해야 한다!
※ 참고 자료
React 공식 문서
React Hooks에 취한다 - useMemo 제대로 사용하기