[React] Hooks(4) useMemo, useCallback

JiHyun·2023년 3월 6일
0
post-thumbnail

렌더링의 발생 조건

  • 컴포넌트에서 state가 바뀌었을 때
  • 컴포넌트가 내려받은 props가 변경되었을 때
  • 부모 컴포넌트가 리렌더링 된 경우 자식 컴포넌트도 모두 리렌더링

앞서 이전 글에서 말했듯 렌더링이 자주 일어난다는건 리액트에서 좋은 의미는 아니다. 우린 비용이 발생하는 것을 최대한 줄이는 작업을 할 필요가 있다. 이런 작업을 최적화(Optimization) 라고 부른다.
최적화를 위한 대표적인 방법이 3가지가 있다.

useMemo : 값을 캐싱

useMemo에서 Memo는 Memoization 을 뜻한다. Memoization이란 동일한 값을 리턴하는 함수를 반복적으로 호출해야 한다면 맨 처음 값을 계산할때 해당 값을 메모리에 저장해서 필요할때마다 또 다시 계산하지 않고 메모리에서 꺼내서 재사용하는 기법이다.

함수형 컴포넌트는 말그대로 컴포넌트 함수를 호출할때 실행되고 렌더링되면 모든 내부 변수들이 초기화된다.

function Component() {
  const value = calculate();
  return <div> {value} </div>
}

function calculate() {
  // 매우 무거운 작업
  return 100
}

여기서 calculate는 아주 무거운 작업을 하는 함수라고 가정하자. 화면이 렌더링이 될때마다 함수의 내부 변수가 초기화되고 매번 value라는 변수에 calculate 함수가 매번 할당되면 아주 비효율적일 것이다. 왜냐면 calculate라는 함수는 무의미한 계산을 반복해서 value 라는 변수에 반복적으로 할당되기 때문이다.
useMemo를 사용하면 처음 함수를 호출해서 계산된 결과값이 메모리에 저장되어서 컴포넌트가 반복적으로 렌더링 될때마다 이전에 저장한 결과값을 메모리에서 꺼내 재사용한다.

useMemo는 2개의 인자를 받는다. 첫번째 인자는 콜백함수로 Memoization 해줄 값을 리턴하는 함수이다. 이 콜백함수가 리턴하는 값이 바로 useMemo가 리턴해주는 값이 된다.
두번째 인자로 의존성 배열을 받는데 배열안에 요소의 값이 업데이트 될때만 콜백함수를 호출해서 Memoization 해준 값을 업데이트해서 다시 Memoization 해준다.

useCallback : 함수를 캐싱

useCallback또한 Memoization 기법으로 컴포넌트의 성능을 최적화시켜주는 도구이다.
useMemo와 다른 점은 값을 저장하는게 아닌 콜백함수 자체를 메모리에 저장하는 것이다. 함수도 하나의 객체이기에 메모리에 변수로 할당해서 저장이 가능하다.

함수형 컴포넌트에서 렌더링된다는건 함수가 호출된다는 말과 동일하다. 그럼 컴포넌트의 모든 내부 변수들이 초기화된다. 렌더링 될때마다 특정 변수에 할당된 함수(A)도 초기화되고 새로 만들어진 함수(B)가 할당된다. 만약 이 함수(A)를 useCallback을 사용하여 Memoizaion을 해주면 컴포넌트가 다시 렌더링이 되더라도 함수(A)가 초기화되는걸 막을 수 있다. 그 말은 즉 컴포넌트가 처음 렌더링될때 함수가 만들어지고 그 함수가 메모리에 저장되며 이후에 렌더링이 일어나도 새로 함수를 다시 만들어서 할당되는게 아닌 이미 할당받은 함수를 계속 재사용해서 사용된다는 말이다.

function Component() {
  
  const calculate = useCallback((num) => {
    return num + 1
  }, [item]);
  
  ...
}

useCallback은 useMemo와 마찬가지로 2개의 인자를 받는다. 첫번째 인자로 콜백함수를, 두번째 인자로 의존성 배열을 받는다. 배열안에 요소의 값이 업데이트 될때만 함수가 새로 만들어지고 변수에 할당되는 것이다.

useMemo와 useCallback은 꼭 필요할때만 사용해야한다. 값 혹은 함수를 재활용하기위해 따로 메모리를 사용해서 저장하기 때문에 불필요한 데이터까지 모두 Memoization 해버리면 오히려 성능이 악화될 수 있다.

React.memo : 컴포넌트를 캐싱

React.memo는 react에서 제공하는 고차 컴포넌트이다.
고차컴포넌트는 영어로 Higher Order Component라고도 불리며 줄여서 HOC라고도 한다. HOC는 어떤 컴포넌트를 인자로 받아서 최적화된 새로운 컴포넌트를 반환해주는 함수이다. 이렇게 최적화된 컴포넌트는 렌더링이 되어야할 상황에 놓일때마다 Prop Check라는걸 해준다. Props의 변화를 확인하고 변화가 있으면 렌더링을 하고 변화가 없으면 기존에 렌더링된 내용을 재사용한다.
처음 렌더링을 하고 렌더링된 컴포넌트를 새로운 메모리에 저장한다. 그리고 부모컴포넌트의 렌더링이 있을때마다 prop check를 해서 변화가 없다면 메모리에 저장된 데이터를 재사용하는 것이다.
React.memo또한 렌더링을 최소화 시켜서 이득을 볼 수 있지만 이또한 무분별하게 사용하면 오히려 성능을 악화시킬 수 있다. 컴포넌트를 Memoizing할때 메모리를 추가적으로 사용해서 렌더링된 결과를 어딘가에 저장하기 때문이다.

React.memo를 사용해야하는 예시
1. 컴포넌트가 같은 props로 자주 렌더링 될때
2. 컴포넌트가 렌더링 될때마다 복잡한 로직을 처리해야 할때

이외의 경우는 React.memo를 꼭 사용해야하는지를 10번(?)정도 더 생각하도록 하자

profile
비전공자의 개발일기📝

0개의 댓글