[React]useMemo, useCallBack

LMH·2022년 11월 30일
0
post-thumbnail

이전 포스팅에서 함수형 컴포넌트를 사용할 때 useState, useEffect를 활용하는 방법에 대해서 정리했습니다. 이 두가지 hook을 사용하면 대부분의 원하는 웹페이지를 구현할 수 있습니다. 하지만 웹서비스를 제공하기 위해 컴포넌트를 최적화하는 단계가 남아 있습니다. 이번에 정리할 useMemo와 useCallBack을 이용하면 렌더링되는 과정에서 발생하는 불필요한 작업을 최소화할 수 있습니다.

Memoization(메모이제이션)

우선 우리가 리액트에서 함수형 컴포넌트를 구현하여 개발을 진행한다는 것은 렌더링 될 때마다 그 함수가 계속해서 실행이 된다는 것을 의미합니다. 그렇기 때문에 컴포넌트 내부에 있는 변수와 함수들이 계속해서 초기화 됩니다. 이때, Meoization은 최적화 기법으로 반복적으로 사용되는 값을 메모리에 캐싱해두고 필요할 때 다시 꺼내어 사용하는 것 입니다.

useMemo

useMemo는 useEffect와 마찬가지로 콜백함수와 의존성 배열을 전달인자를 받습니다. 그리고 콜백함수가 리턴하는 값을 메모리에 저장합니다. 그리고 의존성 배열에 있는 값이 변할 때에만 전달받은 콜백함수를 실행하여 리턴하는 값을 count에 할당하고 저장합니다.

import { useState, useMemo } from "react";

export default function App() {
  const [num, setNum] = useState(0);
  const count = useMemo(() => {
    return num + 1;
  }, [num]);

  const plus = () => {
    setNum(num + 1);
  };

  return (
    <div>
      <div> num : {num}</div>
      <div> count : {count}</div>

      <button onClick={plus}>Click me</button>
    </div>
  );
}

위의 코드에서 count 값은 메모리에 저장되고 렌더링이 발생해도 그 값을 유지합니다. 의존성 배열에 num값이 포함 되어 있기 때문에 setNum 함수를 통해 num값을 변경하면 그 때마다 count값이 num에 1을 더한 값으로 변한 후 렌더링 됩니다.

useCallBack

useMemo가 값을 저장한다면, useCallback은 전달 받은 콜백함수를 메모리에 저장합니다. 그리고 의존성 배열에 있는 값이 변할 때에만 전달받은 콜백함수인 calculate를 메모리에 저장하여 사용합니다.

useCallback Hook을 사용하면 그 함수가 의존하는 값들이 바뀌지 않는 한 기존 함수를 계속해서 반환합니다. 아래의 코드에서는 num 값이 동일하다면 다음 렌더링 때 이 함수를 다시 사용합니다.

일반적으로 useCallback만 사용해서는 useMemo에 비해 최적화 효과가 미미합니다. useCallback은 함수를 호출을 하지 않는 Hook이 아니라, 그저 메모리 어딘가에 함수를 꺼내서 호출하는 Hook이기 때문입니다. 그래서 단순히 함수를 반복해서 생성하지 않기 위해 useCallback을 사용하면 메모리적으로 낭비가 될 수 있습니다.

import { useState, useMemo, useCallback } from "react";

export default function App() {
  const [num, setNum] = useState(0);
  const count = useMemo(() => {
    return num + 1;
  }, [num]);

  const plus = () => {
    setNum(num + 1);
  };
  const calculate = useCallback((num) => {
    return num**2
  }, [num] )
    return (
    <div>
      <div> num : {num}</div>
      <div> count : {count}</div>
      <div>result : {calculate(count)}</div>
      <button onClick={plus}>Click me</button>
    </div>
    )
}

useCallback과 참조 동등성

리액트에서는 리렌더링 시 함수를 새로 생성해서 호출 하기 때문에 새로 만들어져서 호출된 함수는 기존의 함수와 같은 함수가 아닙니다. 그러나 useCallback을 이용해 함수 자체를 저장해서 다시 사용하면 함수의 메모리 주소 값을 저장했다가 불러온다면 항상 같은 메모리를 가지는 함수를 불러 올 수 있습니다.

따라서, 컴포넌트 함수 내에서 다른 함수의 인자로 넘기거나 자식 컴포넌트의 prop으로 넘길 때 useCallback을 활용한다면 예상치 못한 성능 문제를 막을 수 있습니다.

profile
새로운 것을 기록하고 복습하는 공간입니다.

0개의 댓글