useCallback 함수

Dodam·2023년 9월 14일
0

[React]

목록 보기
4/12
post-thumbnail

useCallback

useCallback은 함수 자체를 메모이제이션(memoization) 해준다.
useMemo가 함수의 리턴값을 메모이제이션한다면, useCallback은 함수를 기억해둔다.

useCallback은 첫번째 인자로 메모이제이션할 콜백 함수, 두번째 인자로 의존성 배열을 작성해주면 된다.

const memoizedCallback = useCallback(함수, 배열);

두 번째 인자인 의존성 배열 값이 업데이트 되지 않는 이상
useCallback으로 감싼 함수는 리렌더링이 될 때 다시 함수 객체를 생성하여 변수에 할당하지 않는다.

예를 들어, 어떤 React 컴포넌트 함수 안에 함수가 선언되어 있다면, 이 함수는 해당 컴포넌트가 렌더링될 때마다 새로운 함수가 생성된다.
하지만 useCallback을 사용하면, 해당 컴포넌트가 렌더링 되더라도 그 함수가 의존하는 값들이 바뀌지 않는 한 기존 함수를 계속해서 반환한다.


  • 두 번째 인자로 빈 배열을 넘긴 경우
    처음에만 함수 객체를 만들어서 변수에 할당하고, 이후부터는 이미 만든 것을 계속해서 사용한다.

    const add = useCallback(() => x + y, []);
  • 두 번째 인자로 빈 배열이 아닌 다른 값을 넣은 경우
    값이 변경되어 리렌더링 될 때, 해당 useCallback의 함수도 새로운 함수 객체를 만들어서 변수에 할당한다.

    const add = useCallback(() => x + y, [x, y]);

    즉, x 또는 y 값이 바뀌면 새로운 함수가 생성되어 add 변수에 할당되고,
    x와 y값이 동일하다면 다음 렌더링 때 이 함수를 재사용한다.

자바스크립트의 함수 동등성

useCallback 함수를 언제 사용해야 하는지 이해하기 위해서
자바스크립트에서 함수 간의 동등함이 어떻게 결정되는지 알아야 한다.

> const add1 = () => x + y;
undefined
> const add2 = () => x + y;
undefined
> add1 === add2
false

자바스크립트에서는 함수도 객체로 취급되므로 메모리 주소에 의한 참조 비교가 일어난다.
따라서 add1과 add2 함수가 동일한지 === 연산자를 통해 비교해보면 false가 반환된다.

이러한 자바스크립트의 특성은 React 컴포넌트 함수 내에서 어떤 함수를 다른 함수의 인자로 넘기거나,
자식 컴포넌트의 prop으로 넘길 때 예상치 못한 성능 문제로 이어질 수 있다.

의존 배열로 함수를 넘길 때

React hook 함수들이 불필요한 작업을 줄이기 위해서 두 번째 인자로,
첫 번째 함수가 의존해야하는 배열을 받는다.

예를 들어, useEffect 함수는 두 번째 인자로 넘어온 의존성 배열이 변경될 때만
첫 번째 인자로 넘어온 함수를 호출한다.

ex. fetchUser 함수

다음 컴포넌트에서 API를 호출하는 코드는 fetchUser 함수가 변경될 때만 호출된다.
여기서 자바스크립트가 함수의 동등성을 판단하는 방식 때문에 예상치 못한 무한 루프에 빠지게 된다. fetchUser는 함수이기 때문에, userId 값이 바뀌는 것과 상관없이 컴포넌트가 렌더링될 때마다 새로운 참조값으로 변경이 된다. 그러면 useEffect 함수가 호출되어 user 상태값이 바뀌고 그러면 다시 렌더링되고, 또 다시 useEffect 함수가 호출되는 악순환이 반복된다.

이와 같은 상황에서 useCallback 함수를 이용하면 컴포넌트가 다시 렌더링 되더라도 fetchUser 함수의 참조값을 동일하게 유지시킬 수 있다. 따라서 처음에 의도했던 대로, useEffect로 넘어온 함수는 userId 값이 변경되지 않는 한 재호출되지 않는다.
profile
Good things take time

0개의 댓글