본문 바로가기

개발이야기/웹개발

[코드잇 스프린트 풀스택 4기] 리액트 useMemo, useCallback

반응형
  1. 모두 리액트에서 ‘메모이제이션’을 담당하는 hook
  2. **메모이제이션(memoization)**이란 동일한 계산을 반복해야할 때 계산의 결과를 캐싱하고 이를 재사용하도록 하는 기술
    1. 불필요한 계산을 줄여줌
    2. 성능향상, 코드 간결성
  3. useMemo
    1. 메모이제이션된 값을 반환하는 리액트 hook
    2. const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
    3. 첫번째 인자는 값을 연산하고 반환하는 함수, 두번째 인자는 의존성 배열
      1. 렌더링 시 의존성 배열값의 변경 여부에 따라 실행
      2. 의존성 배열이 없으면 렌더링할 때마다 매번 실행
    4. 컴포넌트내에 특정 변수가 변경되었을 때에만 실행되면 되는 코드가 있을 경우 useMemo를 사용하면 불필요한 함수 실행을 줄일 수 있음
    5. 주의할 점
      1. 계산에 대한 결과가 메모되어 있으므로 계산에 대한 입력이 변경되지 않으면 업데이트되지 않는다. 즉 계산에 대한 입력이 일정하게 유지되는 경우에만 유용
      2. 메모된 결과를 확인할 때마다 연산을 수행해야 하므로 잦은 변동이 있을 경우 오히려 성능이 악화될 수 있음
      3. 메모리 사용
      4. 남발 시 코드 복잡성
  4. useCallback
    1. 메모이제이션된 함수를 반환하는 리액트 hook
    2. 첫번째 인자는 반환할 함수, 두번째 인자는 의존성 배열
    3. 사실 렌더링시마다 함수를 선언하는 것은 성능상 큰 영향을 끼치지 않는다. 그렇다면 왜 사용하는가?
    4. 자바스크립트에서 함수는 객체다. 컴포넌트가 렌더링 될때마다 선언되는 함수는 모두 다른 참조값을 가지므로 다른 객체이다. 이러한 함수를 useEffect의 디펜던시로 사용하면 무한 루프에 빠지게 된다. 이때 이 함수를 useCallback으로 정의하면 재선언되는 것이 아니라 메모리에 저장해둔 함수를 재사용하게 되므로 무한 루프 문제를 해결할 수 있다.
  5. useMemo와 useCallback을 사용해야 하는 경우
    1. 연산 혹은 처리량이 매우 많아서 렌더링의 문제가 되는 경우, 리렌더시 비용 절감을 위해서 useMemo를 사용하자
    2. 함수 자체가 매우 복잡하거나, 다시 계산하는데 비용이 많이 드는 경우에 useCallback을 사용하자.
    3. 자식 컴포넌트에서 useEffect가 반복적으로 트리거 되거나, 무한 루프에 빠질 위험이 있을 때 useMemo, useCallback을 사용하자
    4. 자식 컴포넌트에 함수를 props로 넘길 때, 불필요한 렌더링이 일어난다고 판단된다면 useCallback으로 함수 동등성을 유지해주자.
    5. 사용자의 입력값이 map 혹은 filter 등을 사용하여 이후 렌더링에서도 동일한 참조를 사용할 가능성이 높을 경우 useMemo를 사용해서 메모이제이션을 적용하자
    6. 리액트 상위 트리에서, 부모가 리렌더링 될 때 자식 컴포넌트까지의 렌더링 전파를 막고 싶을 때 useMemo를 사용하자. 자식 컴포넌트가 useMemo로 메모이제이션 컴포넌트일 경우, 메모이제이션된 props를 사용해 필요한 부분만 리렌더링 할 수 있다.
    7. ref 함수를 부수작용(side effect)와 함께 전달하거나, ref로 wrapper 함수를 만들 때 useMemo를 사용하자. 리액트는 ref 함수가 변경될 때 마다 과거 값을 null로 호출하고 새로운 함수를 호출하기 때문인데, 이 경우 ref 함수의 이벤트 리스너가 변경되는 등의 불필요한 작업이 일어날 수 있다.
반응형