React - useCallback()

gyu0714·2022년 11월 7일
0

Hooks

목록 보기
6/9
post-thumbnail

useCallback()

const memoizedCallback = useCallback(() => {doSomething(a, b)}, [a,b]);

메모이제이션된 콜백을 반환한다.
인라인 콜백과 그것의 의존성 값의 배열을 전달한다. useCallback은 콜백의 메모이제이션된 버전을 반환한다. 그 메모이제이션된 버전은 콜백의 의존성이 변경될 때에만 변경이된다. 불필요한 렌더링을 방지하기 위해(shouldComponentUpdate를 사용하여) 참조의 동일성에 의존적인 최적화된 자식 컴포넌트에 콜백을 전달 할 때 유용하다.

💡useCallback(fn, deps) 는 useMemo(() => fn, deps)와 같다.

  • 메모이제이션을 다시 계산할 필요가 없도록 값을 캐싱하는 것이다.
  • 이를 통해 리소스 집약적인 기능을 분리하여 모든 렌더링에서 자동으로 실행되지 않도록 할 수 있다.
  • useCallback 종속성 중 하나가 업데이트될 때만 실행된다.

지켜야할 규칙

useMemo와 useCallback을 사용하지 말아야할 경우

  1. host 컴포넌트(div, span, a, img... 등)에 전달하는 모든 항목에 대해 쓰지 말아야한다. 리액트는 여기에 함수 참조가 변경되었는지 신경쓰지 않는다.(ref는 여기서 제외 된다.)
  2. leaf 컴포넌트에는 쓰지 말아야한다.
  3. useCallback, useMemo의 의존성 배열에 완전히 새로운 객체와 배열을 절달해서는 안된다. 이는 항상 의존성이 같지 않다는 결과를 의미하며, 메모이제이션을 하는데 소용이 없다. useEffect, useCallback, useMemo의 종속성은 참조 동일성을 확인한다.
// 사용 X
const x = ['hello'];
const cb = useCallback(() => {}, [props, x])

const [a, ...rest] = someArray;
const cb = useCallback(() = {}, [rest])
  1. 전달하려는 항목이 새로운 참조여도 상관없다면, 사용하지 말아야 한다. 매번 새로운 참조여도 상관없는데, 새로운 참조라면 메모이제이션하는 것이 의미가 없다.

    host 컴포넌트 : 호스트 환경(브라우저 또는 모바일)에 속하는 플랫폼 컴포넌트를 의미한다. DOM 호스트의 경우, div, img와 같은 요소가 될 수 있다.
    leaf 컴포넌트 : DOM에서 다른 컴포넌트를 렌더링하지 않는 컴포넌트(html 태그만 렌더링하는 컴포넌트)

useMemo와 useCallback 을 사용해야 하는 경우

  1. 하위트리에 많은 Consumer가 있는 값을 Context Provider에 전달해야 하는 경우 useMemo를 사용하는 것이 좋다. "<ProductContext.Provider value = {{id, name}}>"의 경우, 어떤 이유로든 해당 컴포넌트가 리렌더링 된다면 id, name이 동일하더라도 매번 새로운 참조를 만들어 죄다 리렌더링 될 것이다.
  2. 계산 비용이 많이 들고, 사용자의 입력 값이 map과 filter을 사용했을 때와 같이 렌더링 이후로도 참조적으로 동일할 가능성이 높은경우, useMemo를 사용하는 것이 좋다.
  3. ref 함수를 부수작용과 함께 전달하거나, mergeRef-style과 같이 wrapper 함수 ref를 만들 때 useMemo를 쓴다. ref 함수가 변경이 있을 때마다, 리액트는 과거 값을 null로 호출하고 새로운 함수를 호출한다. 이 경우 ref 함수의 이벤트 리스너를 붙이거나 제거하는 등의 불필요한 작업이 일어날 수 있다. 예를들어, useIntersectionObserver가 반환하는 ref의 경우 ref 콜백 내부에서 observer의 연결이 끊기거나 연결되는 등의 동작이 일어날 수 있다.
  4. 자식 컴포넌트에서 useEffect가 반복적으로 트리거되는 것을 막고 싶을 때 사용한다.
  5. 매우 큰 리액트 트리 구조 내부에서, 부모가 리렌더링 되었을 때 이에 다른 렌더링 전파를 막고 싶을 때 사용. 자식 컴포넌트가 React.memo, ReactPureComponent일 경우, 메모이제이션된 props를 사용하게 되면 딱 필요한 부분만 리렌더링 될 것이다.

React DevTools Profilter를 사용하면 컴포넌트의 리렌더링 속도가 느린 경우, 상태 변경이 일어났을 때 얼마나 렌더링 시간이 걸렸는지 조사할 수 있다. 이렇게 하면 거대한 계단식 리렌더링을 방지하기 위해 React.memo를 사용할 위치를 찾을 수 있고, 필요한 경우 useCallback, useMemo를 사용하여 상태변경을 더 효율적으로 만들 수 있다.

profile
gyu0714

0개의 댓글