useMemo와 useCallback에 대해 알아보기 전에 Memoization
에 대해 알아야 합니다.
메모이제이션은 알고리즘 시간에 자주 나오는 개념이라고합니다.
memoization이란 기존에 수행한 연산의 결과값을 어딘가에 저장해두고, 동일한 입력이 들어오면 재활용하는 프로그래밍 기법을 말합니다.
memoization을 적절히 적용한다면 중복 연산을 피할 수 있기 때문에 메모리를 조금 더 쓰더라도 어플리케이션의 성능을 최적화할 수 있습니다.
메모제이션 된
값
을 반환한다.
useMemo(() => function, dependency);
useMemo는 deps가 변하면, () => function 이라는 함수를 실행
하고, 그 함수의 반환 값을 반환한다.
deps는 dependency이며, useMemo가 deps라는 것에 의존
한다는 뜻입니다.
import React, { useState, useCallback, useMemo } from "react";
export default function App() {
const [x, setX] = useState(0);
const [y, setY] = useState(0);
// useMemo 사용하기
useMemo(() => console.log(x), [x]);
// 두 개의 버튼을 설정했다. x버튼만이 ex를 변화시킨다.
return(
<>
<button onClick={() => setX(curr => curr + 1)}>X</button>
<button onClick={() => setY(curr2 => curr2 + 1)}>Y</button>
</>
);
}
위 코드는 X라는 버튼을 누를 때, x
라는 상태값이 변화하는 코드입니다.
useMemo(() => console.log(x), [x]);
에서 deps는 [x]입니다.
x가 변할 때만 () => console.log(x)가 실행됩니다.
따라서 X 버튼을 누를 때에만 콘솔창에 x값이 출력됩니다.
Y 버튼을 누르더라도 APP 이라는 함수 컴포넌트가 전부 재실행(rerendering)되지만,
x라는 값은 변하지 않았기 때문에 useMemo에는 아무런 변화가 없습니다.
메모이제이션 된
함수
를 반환합니다.
useMemo는 함수를 실행하지만, useCallback의 경우는 함수를 반환하는 차이점이 있습니다.
useCallback(function, dependency);
useCallback은 deps가 변한다면, function이라는 새로운 함수를 반환
합니다.
import React, { useState, useCallback, useMemo} from "react";
export default function App() {
const [x, setX] = useState(0);
const [y, setY] = useState(0);
// useCallback 이 () => {console.log(y)} 라는 함수를 반환한다.
const useCallbackReturn = useCallback(() => {console.log(y)}, [x]);
// useCallback 이 담겨있는 함수를 실행
useCallbackReturn()
return (
<>
<button onClick={() => setX((curr) => (curr + 1))}>X</button>
<button onClick={() => setY((curr2) => (curr2 + 1))}>Y</button>
</>
);
}
위의 useCallback은 () => console.log(y)
라는 함수를 반환해주고 있습니다.
다음 useCallback 코드는 다음의 순서대로 진행됩니다.
1. 처음 컴포넌트가 시작될 때 실행 () => console.log(0)
2. x가 변할 때까지 함수는 () => console.log(0)
3. x가 변한다면 그제서야 y의 값을 가져와서 () => console.log(새로운 값)
예를 들어 Y버튼을 다섯번 누르면, y라는 상태의 값이 1씩 증가할 것입니다.
위의 실행 영상을 보면 Y 버튼을 계속 눌러도 console창에는 0을 반환합니다.
(그 동시에 y의 상태 값은 계속 증가합니다)
그리고 나서 X 버튼을 누르면 x라는 변수(deps)가 변하자 마자 console창에 5를 반환합니다.
deps가 변해야 함수 컴포넌트와 상태값(y)를 공유하는 것입니다.
이와같이 useCallback은 함수와는 상관없는 상태값이 변할 때,
함수 컴포넌트에서 불필요하게 함수를 업데이트하는 것을 방지해줍니다.
다만, deps를 잘못 설정하면 아무리 함수 컴포넌트를 재실행하더라도 함수가 변하지 않으면서
원하는 방향으로 실행되지 않을 수 있으므로 섬세한 컨트롤이 필요합니다.
🚨하지만 useMemo도 마찬가지로 Y 버튼을 5번 눌러도, X 버튼을 누르지 않는다면 실행되지 않습니다.
추가로, react 공식문서에서도 아래의 두 식은 같습니다.
useMemo((...)=>fn, deps) === useCallback(fn, deps)