티스토리 뷰

React

[React] 최적화 (useMemo, React.memo)

_Woogie 2022. 12. 17. 18:37

먼저, 리액트에서 리렌더링되는 조건을 알아보자

1. 함수 컴포넌트 자기자신의 상태가 변경될 때
2. 부모 컴포넌트로부터 받은 prop의 상태가 변경될 때
3. 부모 컴포넌트의 상태가 변경될 때

 

리액트는 이름답게 변화를 감지하여 리렌더링이 되는것이 특징이고, 이런 특징은 빠른 개발속도를 자랑하지만 코드를 잘못 짜면 성능적으로 봤을 때 단점이 될 수도 있다.

 

예를 들어서 십억번의 연산을 하는 컴포넌트가 있다고 할때, 리렌더링 될 때마다 십억번의 연산을 하게 되면 큰 성능낭비가 될 수 있다.

 

아래 예제로 확인해보자.

1부터 n만큼의 숫자를 더하고 버튼 클릭을 할 때마다 label뒤에 ":"을 하나씩 붙혀주는 코드다.

// App.js
import {useState} from "react";
import ShowSum from "./components/DAY45/ShowSum";

function App() {
  const [label, setLabel] = useState("Result");
  return (
    <div>
      <button onClick={() => setLabel(label + ":")}>add colon</button>
      <ShowSum label={label} n={100} />
    </div>
  );
}

export default App;
// ShowSum.js
function sum(n) {
  console.log("start");
  let result = 0;
  for (let i = 1; i <= n; i++) {
    result += i;
  }
  console.log("finish");
  return result;
}

const ShowSum = ({ label, n }) => {
  const result = sum(n);
  return (
    <span>
      {label}: {result}
    </span>
  );
};

export default ShowSum;

 

 

100번의 연산쯤은 식은죽먹기로 엄청 빠르게 동작한다.

이제 n을 십억(1,000,000,000)으로 바꾸고 클릭을 누르게 되면 1초~2초 정도 걸린 뒤에 finish가 콘솔에 찍힌다.

 

이렇게 많은 연산을 하는 함수를 매번 리렌더링할 수 없을때 useMemo를 사용한다.

 

useMemo 사용법은 매우 간단하다.

 

useMemo 사용법

import {useMemo} from "react";

...

const result = useMemo(() => sum(n), [n])

첫번째 파라미터에는 어떻게 연산할지 정의하는 함수를 넣어주고, 두번째 파라미터에는 의존성 배열을 설정해줘서 배열안의 값이 바뀔때만 다시 연산을 하는 방법이다.

 

이렇게 값을 저장하는 useMemo는 저장만 하는게 아니라 이전에 계산 한 값을 재사용한다는 의미가 크다.

 

useMemo는 값을 재활용하기 위해 따로 메모리를 소비해서 저장을 해놓는다.

그렇기 때문에 불필요한 값까지 모두 Memoization 하면 성능이 안좋아 질 수 있다.

따라서 useMemo는 꼭 필요할때만 사용 하는 것이 좋다.

 

 

여기서, 다시 리액트가 리렌더링 되는 조건을 다시 보자면

1. 함수 컴포넌트 자기자신의 상태가 변경될 때
2. 부모 컴포넌트로부터 받은 prop의 상태가 변경될 때
3. 부모 컴포넌트의 상태가 변경될 때

 

1번, 2번은 자식컴포넌트의 상태와 연관이 있기 때문에 리렌더링 되도 뭐 오케이.

근데 3번은 부모의 상태가 바뀐다고 자식한테도 영향을 주면 뭔가 아니꼽지않은가? 자식 상태는 바뀌지 않았는데.

불합리하다고 생각한다.

 

이럴때 간단하게 사용해줄 수 있는게 React.memo메서드다.

 

먼저 React.memo를 사용하지 않는다면

function App() {
  const [count, setCount] = useState(0);
  
  return (
    <div>
      <button onClick={() => setCount(count + 1)}>+</button>
      <span>{count}</span>
      <BoxComponent/>
    </div>
  );
}

export default App;
const BoxComponent = () => {
  const style = {
    width: 200,
    height: 200,
    backgroundColor: "red",
  };
  console.log("렌더링");
  return <div style={style}></div>;
};

export default BoxComponent;

 

위 사진처럼 가만히 있는 자식 컴포넌트도 계속 렌더링되는걸 확인할 수 있다.

 

이제 React.memo를 사용해보자

 

React.memo 사용법

매우 간단하다. 자식컴포넌트를 React.memo()로 감싸주기만 하면 된다.

import React from "react";

const BoxComponent = React.memo(() => {
  const style = {
    width: 200,
    height: 200,
    backgroundColor: "red",
  };
  console.log("렌더링");
  return <div style={style}></div>;
});

export default BoxComponent;

 

 

 


참고

 

17. useMemo 를 사용하여 연산한 값 재사용하기 · GitBook

17. useMemo 를 사용하여 연산한 값 재사용하기 이번에는 성능 최적화를 위하여 연산된 값을 useMemo라는 Hook 을 사용하여 재사용하는 방법을 알아보도록 하겠습니다. App 컴포넌트에서 다음과 같이 co

react.vlpt.us

 

 

[React] useMemo 사용법 및 예제

[useMemo] useMemo는 컴포넌트의 성능을 최적화시킬 수 있는 대표적인 react hooks 중 하나입니다. useMemo에서 Memo는 Memoization을 뜻합니다. memoization이란 기존에 수행한 연산의 결괏값을 어딘가에 저장해

itprogramming119.tistory.com