useMemo와 useCallback은 계산 결과나 함수 참조를 재사용하기 위한 memoization hook입니다. useMemo는 어떤 계산의 결과 값을 재사용하고 싶을 때 사용합니다. 예를 들어 큰 배열을 filtering하거나 sorting한 결과를 dependency가 바뀌지 않는 동안 재사용할 수 있습니다. useCallback은 함수 자체의 참조를 안정적으로 유지하고 싶을 때 사용합니다.
보통 memoized child component에 callback을 넘기거나 effect dependency에서 함수 참조가 계속 바뀌는 것을 줄이고 싶을 때 사용합니다. 둘 다 render를 막는 마법은 아니고, dependency 비교와 memoization 비용이 있으므로 실제로 필요한 곳에 쓰는 것이 좋습니다.
꼬리질문
조금 더 깊게 물어본다면
답변 뒤에 이어질 수 있는 질문들을 하나씩 열어볼 수 있어요.
useCallback을 쓰면 child 리렌더링이 항상 막히나요?
아닙니다. child가 React.memo로 감싸져 있고, 다른 props도 안정적이어야 효과가 있습니다. 함수 참조만 안정적이어도 다른 객체 prop이 매번 새로 만들어지면 child는 다시 렌더링될 수 있습니다.
즉, useCallback 단독으로 리렌더링 방지가 보장되는 것은 아닙니다.
useMemo 안에 side effect를 넣어도 되나요?
좋지 않습니다. useMemo는 render 중 계산 결과를 memoize하는 용도입니다. side effect는 useEffect 같은 effect hook에서 처리해야 합니다.
React가 memoized 값을 버릴 수도 있다고 생각하면, useMemo에 side effect를 넣는 것은 위험합니다.
dependency array를 일부러 비워도 되나요?
정말 외부 값에 의존하지 않는 경우에는 가능합니다. 하지만 내부에서 props나 state를 읽는데 dependency를 비우면 stale value를 사용할 수 있습니다.
lint rule이 dependency 누락을 알려주는 이유도 이런 버그를 줄이기 위해서입니다.
useMemo와 useCallback을 언제 제거해도 되나요?
계산 비용이 작거나 child memoization과 연결되어 있지 않거나, profiler에서 효과가 보이지 않는다면 제거해도 됩니다. 코드가 단순해지는 것이 더 큰 이득일 수 있습니다.