const memoizedCallback = useCallback( () => { doSomething(a, b); }, [a, b], ); const memoizedCallback = useCallback(function, deps); const memoizedCallback = useCallback(함수, 배열);
  • 정의
    • 특정 함수를 새로 만들지 않고 재사용하고 싶을때 사용
    • 메모이제이션된 콜백을 반환
    • 메모이제이션 : 동일한 계산을 반복해야 할 때, 이전에 계산한 값을 메모리에 저장함으로써 동일한 계산의 반복 수행을 제거하여 프로그램 실행 속도를 빠르게 하는 기술 (출처 : https://ko.wikipedia.org/wiki/메모이제이션)
    • 그 메모이제이션된 콜백은 콜백의 의존성이 변경되었을 때에만 변경됨
    • 불필요한 렌더링을 방지하기 위해 (예로 shouldComponentUpdate를 사용하여) 참조의 동일성에 의존적인 최적화된 자식 컴포넌트에 콜백을 전달할 때 유용
    • useCallback(fn, deps) 은 useMemo(() => fn, deps) 와 동일함 → useCallback(특정 함수 재사용)은 useMemo(특정 값 재사용)를 기반으로 만들어졌고, 다만 함수를 위해서 사용할 때 더욱 편하게 해준 것뿐
    • 첫 번째 인자로 넘어온 함수를, 두 번째 인자로 넘어온 배열 형태의 함수 실행 조건의 값이 변경될 때까지 저장해놓고 재사용할 수 있게 해줌
    • 예를 들어, 어떤 React 컴포넌트 함수 안에 함수가 선언이 되어 있다면 이 함수는 해당 컴포넌트가 렌더링될 때 마다 새로운 함수가 생성됨. 컴포넌트가 렌더링 될 때마다 함수의 참조 값이 변경됨
    •  
      const add = () => x + y;
       
    • 하지만 useCallback()을 사용하면, 해당 컴포넌트가 렌더링되더라도 그 함수가 의존하는 값들이 바뀌지 않는 한 기존 함수를 계속해서 반환합니다. 즉, x또는 y값이 바뀌면 새로운 함수가 생성되어 add변수에 할당되고, x와 y값이 동일하다면 다음 렌더링 때 이 함수를 재사용합니다.
  • 사용 이유
    • 함수를 선언하는 것 자체는 사실 메모리도, CPU도 리소스를 많이 차지하는 작업은 아니기 때문에 함수를 새로 선언한다고 해서 그 자체만으로 큰 부하가 생길 일은 없음
    • 그러나, 컴포넌트에서 props가 바뀌지 않으면 Virtual DOM에 새로 렌더링하는 것조차 하지 않고 컴포넌트의 결과물을 재사용하는 최적화 작업을 하기 위해 사용
  • 사용해야 할 경우
      1. 참조 동일성이 유지되지 않는 object의 경우
      1. 과도한 계산이 포함된 함수인 경우 : 매번 새로 값을 계산하게 되면 불필요한 연산이 수행되기 때문
⚠️
만약 하위 컴포넌트가 React.memo() 같은 것으로 최적화 되어 있고 그 하위 컴포넌트에게 callback 함수를 props로 넘길 때, 상위 컴포넌트에서 useCallback 으로 함수를 선언하는 것이 유용하다라는 의미이다. 함수가 매번 재선언되면 하위 컴포넌트는 넘겨 받은 함수가 달라졌다고 인식하기 때문이다.
  • React.memo()로 함수형 컴포넌트 자체를 감싸면 넘겨 받는 props가 변경되지 않았을 때는 상위 컴포넌트가 메모리제이션된 함수형 컴포넌트(이전에 렌더링된 결과)를 사용하게 된다.
  • 함수는 오로지 자기 자신만이 동일하기 때문에 상위 컴포넌트에서 callback 함수를 (같은 함수이더라도) 재선언한다면 props로 callback 함수를 넘겨 받는 하위 컴포넌트 입장에서는 props가 변경 되었다고 인식한다.
  • 사용법
    • 인라인 콜백과 그것의 의존성 값의 배열을 전달
    • 주의
      • 의존성 값의 배열이 콜백에 인자로 전달되지는 않음
      • 개념적으로는, 이 기법은 콜백 함수가 무엇일지를 표현하는 방법임
      • 콜백 안에서 참조되는 모든 값은 의존성 값의 배열에 나타나야 함 → 그렇지 않으면 함수 내에서 해당 값들을 참조할때 가장 최신 값을 참조할 것이라고 보장할 수 없기 때문. props 로 받아온 함수가 있다면, 이 또한 deps에 넣어줘야함.
       
  • 장점
    • 자식 컴포넌트의 불필요한 렌더링을 최적화
  • 단점
    • 성능 최적화에는 코드의 복잡성, 유지보수의 어려움, 메모리 증가 등의 단점이 있을 수 있기 때문에 이러한 단점과 이점을 비교해서 useCallback을 사용해야함
  • 참고 사이트