useMemo와 useCallback 훅에 대해 알아보자.
useMemo
useMemo에서 memo는 memoization(메모이제이션)을 의미하고, 메모이제이션이란 값을 캐싱하여 같은 계산을 반복하지 않아도 되게 하는 기술을 말한다.
useMemo는 memoized 값을 리턴하고, 보통 비싼 연산을 계산할 때 사용된다.
컴포넌트는 렌더링시 위에서부터 아래로 코드를 실행하는데, 이런 경우 내부에 비싼 연산이 하나만 있어도 전체 성능을 저해할 수 있기 때문이다.
예를 들어 computeExpensiveValue() 라는 함수가 있을 때
const value = computeExpensiveValue()
대신
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
처럼 useMemo를 사용할 수 있다.
useMemo에 "create" function과 dependencies 배열을 전달한다.
dependencies 중 하나가 변경될 때만 memoized 값을 재연산한다.
그러나 useMemo를 사용할 때 주의할 점은 비싼 연산에만 사용해야한다는 점이다.
왜냐하면 메모이제이션에 대해 설명했듯 값을 메모리에 저장하는데, 비싼 연산이 아닌 모든 연산에 useMemo를 사용하게 되면 useMemo를 불러오는 시간이 포함되 성능 측면에서도 좋지 않고 불필요한 메모리 사용을 하게 되기 때문이다.
useCallback
useCallback도 useMemo와 비슷해보일 수 있다.
하지만 memoized 값을 리턴하는 useMemo와 달리 useCallback은 memoized 콜백을 리턴한다.
useCallback은 불필요한 렌더링을 막기 위해 reference equality(참조의 동일성)에 의존적인 최적화된 하위 컴포넌트에 콜백을 넘길 때 유용하다.
useCallback에 인라인 콜백과 dependencies 배열을 넘긴다.
useCallback을 예제를 통해 더 자세히 살펴보자. (전체 코드는 여기서 확인)
상위 컴포넌트에 랜덤으로 생성하고자 하는 숫자의 갯수('total' state라고 하겠다)를 받는 input element가 있고 하단에는 그냥 'nothing' state를 true와 false로 토글하는, 즉 숫자 생성과는 상관없는 버튼이 있다.
function App() {
const [total, setTotal] = useState(0);
const [nothing, setNothing] = useState(false);
}
상위 컴포넌트에는 갯수만큼 숫자를 생성하는 getRandomNumbers()가 있고 이를 하위 컴포넌트에 넘겨준다.
그러면 하위컴포넌트는 0-5 사이의 랜덤 숫자 여러개 배열을 받아 화면에 표시한다.
그렇다면 여기서 Do nothing 버튼은 랜덤 숫자와는 아무런 관련이 없기 때문에 클릭 이벤트가 발생해도 하위 컴포넌트를 리렌더링해서는 안된다.
비교를 위해 같은 콜백을 하나는 useCallback을 사용하고 하나는 사용하지 않고 각각 다른 하위 컴포넌트에 넘겨주었다.
function App() {
// ...
return (
// ...
<WithCallback getRandomNumbers={getRandomNumbers} />
<WithoutCallback getRandomNumbers2={getRandomNumbers2} />
// ...
);
}
function WithCallback({ getRandomNumbers }) {
const [items, setItems] = useState([]);
useEffect(() => {
console.log('Render WithCallback')
setItems(getRandomNumbers(5));
}, [getRandomNumbers])
return (
<div>
With: {items.join(", ")}
</div>
)
}
useCallback을 사용하지 않고(Without: 이라고 적힌 부분) 그냥 콜백을 넘겨줬을 경우 아래에서 보는 것처럼 Do nothing 버튼을 눌렀을 때도 리렌더링되는 것을 알 수 있다.
이 글에서는 useMemo와 useCallback에 대해서 알아보았다.
useMemo는 비싼 연산을 위해서, useCallback은 하위 컴포넌트에 콜백을 넘기기 위해 사용되며
useMemo는 memoized 값을, useCallback은 memoized 콜백을 리턴하는 차이가 있으므로 각자 알맞는 상황에 사용하도록 하자.
Reference
'개발 > 프론트엔드 (JS & React)' 카테고리의 다른 글
[React & Storybook] 3 - 타입스크립트로 스토리 작성하기 (0) | 2022.09.29 |
---|---|
[React Hooks] Custom Hook examples 커스텀 훅 예제 (0) | 2022.09.27 |
[React Hooks] useReducer 사용해서 Todo list 구현하기 (0) | 2022.09.25 |
[React Hooks] Context API와 컴포넌트 합성(Component Composition) (0) | 2022.09.25 |
[React & Storybook] 2 - 스토리 작성 방법 (1) | 2022.09.23 |