useMemo와 useCallback의 차이
React Hook은 렌더링 최적화를 위한 Hook이 존재한다.
- useCallback과 useMemo가 바로 그 역할을 하는 Hook이다.
useCallback이란?
useCallback 또한 useMemo와 마찬가지로 메모이제이션 기법을 이용한 Hook이다.
- useMemo는 값의 재사용을 위해 사용하는 Hook이라면,
- useCallback은 함수의 재사용을 위해 사용하는 Hook이다.
아래의 Calculator 컴포넌트 내에는 add라는 함수가 선언이 되어 있는 상태이다.
- 이 add 함수는 props로 넘어온 x와 y 값을 더해 <div> 태그에 값을 출력한다.
- 이 함수는 해당 컴포넌트가 렌더링 될 때마다 새롭게 만들어진다.
function Calculator({x, y}){
const add = () => x + y;
return <div> {add()} </div>;
}
useMemo와 마찬가지로, 해당 컴포넌트가 리렌더링 되더라도 그 함수가 의존하고 있는 값인 x와 y가 바뀌지 않는다고 가정해보자.
- 그렇다면 함수 또한 메모리 어딘가에 저장해 뒀다가 다시 꺼내서 쓸 수 있을 것이다.
- 이때 useCallback Hook을 사용하면 그 함수가 의존하는 값들이 바뀌지 않는 한 기존 함수를 계속해서 반환한다.
- 즉 x와 y값이 동일하다면 다음 렌더링 때 이 함수를 다시 사용한다.
/* useCallback를 사용하기 전에는 꼭 import해서 불러와야 한다. */
import React, { useCallback } from "react";
function Calculator({x, y}){
const add = useCallback(() => x + y, [x, y]);
return <div> {add()} </div>;
}
사실 useCallback만 사용해서는 useMemo에 비해 괄목할 만한 최적화를 느낄 수는 없다.
- 왜냐하면 useCallback은 함수를 호출을 하지 않는 Hook이 아니라, 그저 메모리 어딘가에 함수를 꺼내서 호출하는 Hook이기 때문이다.
- 따라서 단순히 컴포넌트 내에서 함수를 반복해서 생성하지 않기 위해서 useCallback을 사용하는 것은 큰 의미가 없거나 오히려 손해인 경우도 있다.
- 따라서, React 컴포넌트 함수 내에서 다른 함수의 인자로 넘기거나 자식 컴포넌트의 props로 함수를 전달해 줄 때 이 useCallback을 사용하기가 좋다.
useCallback과 참조 동등성
useCallback은 참조 동등성에 의존한다.
- React는 JavaScript 언어로 만들어진 오픈소스 라이브러리이기 때문에 기본적으로 JavaScript의 문법을 따라간다.
- JavaScript에서 함수는 객체이다.
- 객체는 메모리에 저장할 때 값을 저장하는 게 아니라 값의 주소를 저장하기 때문에, 반환하는 값이 같을지라도 일치연산자로 비교했을 때 false가 출력된다.
- 아래 코드가 예시이다.
- double1과 double2는 같은 함수를 할당했음에도 메모리 주소 값이 다르기 때문에 같다고 보지 않는다.
- 따라서 두 개의 함수는 동일한 코드를 공유하더라도 메모리 주소가 다르기 때문에, 메모리 주소에 의한 참조 비교 시 다른 함수로 본다.
function doubleFactory(){
return (a) => 2 * a;
}
const double1 = doubleFactory();
const double2 = doubleFactory();
double1(8); // 16
double2(8); // 16
double1 === double2; // false
double1 === double1; // true
이는 React 또한 같다.
- React는 리렌더링 시 함수를 새로이 만들어서 호출을 한다.
- 새로이 만들어 호출된 함수는 기존의 함수와 같은 함수가 아니다.
useCallback을 이용해 함수 자체를 저장해서 다시 사용하면 함수의 메모리 주소 값을 저장했다가 다시 사용한다는 것과 같다고 볼 수 있다.
- 따라서 React 컴포넌트 함수 내에서 다른 함수의 인자로 넘기거나 자식 컴포넌트의 prop으로 넘길 때 예상치 못한 성능 문제를 막을 수 있게 된다.
useCallback를 이용하여 앱 최적화하기
useCallback 사용 전
useCallback 사용 전인 최적화되지 않은 컴포넌트이다.
- input 창에 숫자를 입력하면 콘솔에 “아이템을 가져옵니다.” 가 출력된다. (정상적인 동작)
- 옆의 button dark mode도 눌러보면 이번에도도 “아이템을 가져옵니다.”가 콘솔에 출력된다. (사이드 이펙트)
- 이 동작의 이유는 버튼을 누를 때도 앱이 리렌더링 되므로, App 내부의 getItems() 함수가 다시 만들어진다.
- 새로이 만들어진 함수는 이전의 함수와 참조 비교 시 다른 함수이다.
- 즉, 자식 컴포넌트인 List에 새로운 주소 값을 가진 getItems 함수가 props로 넘겨진다.
- 따라서 List 구성 요소 내의 useEffect Hook은 종속성이 변경됨에 따라 “아이템을 가져옵니다.”를 출력하게 된다.
useCallback 사용 후
useCallback을 이용하여 dark mode 버튼을 눌러도 함수가 불필요하게 다시 호출되지 않는다.
728x90
'FE > React' 카테고리의 다른 글
React.lazy()와 React.Suspense (0) | 2023.05.22 |
---|---|
코드 재사용을 도와주는 Custom Hooks (0) | 2023.05.22 |
React의 렌더링 최적화를 도와주는 useMemo (0) | 2023.05.19 |
React의 Hook의 개념과 사용 규칙 (0) | 2023.05.19 |
React Diffing Algorithm - 상태변화를 감지할 수 있도록 하는 React의 비교 알고리즘 (0) | 2023.05.19 |