React Hooks - useMemo

박정호·2022년 8월 30일
0

React Hook

목록 보기
5/12
post-thumbnail

🚀 Start

리액트를 사용하다보면 랜더링,재랜더링이 될때 함수들이 똑같은 동작을 하여도 연산시 성능을 잡아먹는다. 따라서, 리액트 어플리케이션 성능을 최적화하기위한 연산 결과를 재사용할 방법을 알아보자.

💡 잠깐) 성능최적화 방법

✏️ 리액트에서 컴포넌트 랜더링이 일어나는 경우 4가지
1. props가 변경
2. state가 변경
3. forceUpdate()를 실행
4. 부모 컴포넌트가 랜더링

리액트 컴포넌트는 부모 컴포넌트의 랜더링으로 인해 자식 컴포넌트까지 랜더링된다. 이로 인해 불필요한 랜더링이 일어나고 성능저하 및 손실이 오는 것이다.

✏️ 성능 최적화 방법 5가지

1. state 선언 위치

  • 랜더링은 state의 변화에 따라 일어나기 때문에, state가 선언된 컴포넌트와 하위 컴포넌트는 모두 리랜더링되게 되어 있다. 따라서 state의 선언 위치를 잘 설정해주는 것도 랜더링 횟수를 줄일 수 있는 방법이다.
    예를 들어 a컴포넌트에 필요한 state를 최상위 컴포넌트에 선언한다. 그러면 a컴포넌트에서 랜더링이 일어날 때마다 최상위 컴포넌트와 연결된 또 다른 b,c컴포넌트들까지 랜더링되버리는 것이다.

2. React.memo()

  • React.memo는 컴포넌트를 랜더링하여 그 결과를 메모이징하는데 다음 랜더링이 일어날 때 props가 같으면 메모이징한 내용을 재사용하여 불필요한 리랜더링을 막는다.

3. key값으로 index를 사용 X

  • map함수 사용시 고유 key값을 설정할때 index값으로 설정할 경우 새로운 값 삽입시 리마운트가 일어나고 데이터가 매칭되지 않으므로 오류가 발생한다. 따라서, 반드시 중복되지 않고 고유한 값을 key값으로 설정하자.
    (쉬운 설명: https://www.youtube.com/watch?v=QC3PtSlzp3s)

4. useMemo

  • 종속 변수들이 변하지 않으면 굳이 다시 호출하지 않고 반환한 참조값을 재사용하여 호출 시간을 세이브 하고 하위 컴포넌트의 리랜더링을 막는다.

5. useCallback

참조: React의-렌더링-성능-최적화-방법을-알아보자

🪝 useMemo

useMemo란 성능 최적화를 위하여 연산된 값을 재사용하는 기능을 가진 함수

컴포넌트 내에 함수 값 리턴이 오래 걸린다면 리랜더링 될때마다 함수가 호출되면서 많은 시간이 소요된다.
useMemo는 종속 변수들이 변하지 않으면 함수를 굳이 다시 호출하지 않고 이전에 반환한 참조값을 재사용한다. 이를 통해 함수 호출 시간도 세이브할 수 있고 같은 값을 props로 받는 하위 컴포넌트의 리랜더링도 방지 가능하다.

💡 중요) Memoization
계산된 값을 자료구조에 저장하고 이후 같은 **계산을 반복하지 않고 자료구조에서 꺼내 재사용하는 것으로,메모이제이션의 대표적인 예로는 동적계획법의 탑다운 방식이 있다.

😀 사용방법

useMemo(함수, deps배열 ) 

✏️ 첫 번째 파라미터로 어떤 연산을 할지 함수를 정의

  • useMemo 훅은 이 함수가 반환한 값을 기억한다.

✏️ 두 번째 파라미터에는 의존성(deps) 배열을 입력

  • 배열 안에 넣은 내용이 변경되면 함수를 호출해서 값을 연산. 의존성 배열이 변경되지 않으면 이전에 반환된 값을 재사용한다.

✏️ useMemo는 2개의 인자를 받는다.

  • 첫번째는 결과값을 생성해주는 팩토리 함수, 두번째는 기존 결과값 재활용 여부의 기준이 되는 입력값 배열이다.

예) deps에 전달된 x,y의 변화에 따라서만 연산을 수행하여 z 를 갱신

  • x와 y 값이 이 전에 랜더링했을 때와 동일할 경우, 이 전 랜더링 때 저장해두었던 결과값을 재활용합니다. 하지만, x와 y 값이 이 전에 랜더링했을 때와 달라졌을 경우, () => compute(x, y) 함수를 호출하여 결과값을 새롭게 구해 z에 할당
function MyComponent({ x, y }) {
  const z = useMemo(() => compute(x, y), [x, y]);
  return <div>{z}</div>;
}

🙂 사용예시

✏️ useMemo 사용 X

  • ComponentRender함수가 랜더링 될 때마다 valueProp1 함수 또한 계속 랜더링.
import React from "react";

const expensiveFunction = (prop) => {
// 에너지가 많이 소모되는 계산이 일어난다는 가정을 했을 때,
}
const ComponentRender = ({ prop1, prop2 }) => {
const valueProp1 = computeValueFromProp(prop1);
  return (
    <>
      <div>{valueProp1}</div>
      <div>{prop2}</div>
    </>
  );
};

✏️ useMemo 사용 O

  • 변경되는 props만을 감지해서 다시 계산할 수 있도록 useMemo를 사용해서 성능최적화.
    -> valueProp1 함수는 prop1이 변경될때만 랜더링된다. 만약 prop2가 변경되어 ComponentRender함수가 리랜더링 될 경우엔 prop1은 마지막으로 계산된 값을 사용하게 된다.
import React from "react";

const expensiveFunction = (prop) => {
// 에너지가 많이 소모되는 계산이 일어난다는 가정을 했을 때,
}
const ComponentRender = ({ prop1, prop2 }) => {
const valueProp1 = useMemo(() => {
  return computeValueFromProp(prop1);
}, [prop1]);
  return (
    <>
      <div>{valueProp1}</div>
      <div>{prop2}</div>
    </>
  );
};

예시 출처: https://velog.io/@eassy/React%EC%84%B1%EB%8A%A5-%EC%B5%9C%EC%A0%81%ED%99%94%EC%9D%98-useMemo-useCallback

🧐 useMemo는 언제 사용?

정확히 언제 사용해야할까?
: https://yceffort.kr/2022/04/best-practice-useCallback-useMemo

참조

쉬운 설명: https://www.youtube.com/watch?v=e-CnI8Q5RY4

profile
기록하여 기억하고, 계획하여 실천하자. will be a FE developer (HOME버튼을 클릭하여 Notion으로 놀러오세요!)

0개의 댓글