[짤막글] useMemo를 사용해보자

kysung95·2021년 4월 12일
52

짤막글

목록 보기
3/15
post-thumbnail

안녕하세요. 김용성입니다.
오늘은 react 생태계에서 렌더링 최적화를 위해 사용되는 hook인 useMemo에 대해서 알아보겠습니다.

많은 분들이 useState, useEffect 같은 hook에 대해서는 익숙하지만 useMemo, useCallback에는 익숙하지 않은 것 같아서 이렇게 포스팅을 결정하게 되었습니다. 이번 포스팅에서는 useMemo를 중점적으로 다룬 뒤 다음 포스팅에서 useCallback을 다뤄보도록 하겠습니다.

그럼 시작해보겠습니다.

(이해하는 데에 도움을 주는 컨텐츠를 제공해주신 개발자 이화랑님께 감사드립니다.)

이건 알아두세요!

  • 함수형 컴포넌트는 그냥 함수입니다. 다시 한 번 강조하자면 함수형 컴포넌트는 단지 jsx를 반환하는 함수이죠.

  • 컴포넌트가 렌더링 된다는 것은 누군가가 그 함수(컴포넌트)를 호출하여서 실행되는 것을 말합니다. 함수가 실행될 때마다 내부에 선언되어 있던 표현식(변수, 또다른 함수 등)도 매번 다시 선언되어 사용됩니다.

  • 컴포넌트는 자신의 state가 변경되거나, 부모에게서 받는 props가 변경되었을 때마다 리렌더링 됩니다. 심지어 하위 컴포넌트에 최적화 설정을 해주지 않으면 부모에게서 받는 props가 변경되지 않았더라도 리렌더링 되는게 기본입니다.
    (-[짤막글]react.memo편 참조 )

렌더링 최적화

기본적으로 react는 부모 component로부터 받는 state,props가 변동될 경우 rerendering됩니다. 당연한 것이죠. 하지만 여기에는 분명한 문제가 존재합니다.

예를들어 state,props가 여러가지라면?
state1, state2, state3이 존재하는 상태에서 state1을 변경시켜주었는데 state2, state3도 재계산된다면??
이것이 과연 좋은 rerendering일까요??

useMemo와 useCallback은 이러한 고민을 가질 개발자들을 위해 탄생했다고 보시면 됩니다.
둘이 비슷한 개념이기에 많은 FE 면접에서 useMemo와 useCallback의 차이점을 물어보곤 하죠.
이번 useMemo 포스팅과 다음번에 올라올 useCallback 포스팅을 잘 보시면 이러한 질문에 잘 대처하실 수 있으리라 생각합니다:)

useMemo 사용법

자 간단한 코드를 작성해보겠습니다.
파일 구성은 App.js와 ShowState.js로 구성되어있습니다.

//App.js

import React, { useState } from "react";
import ShowState from "./ShowState";

const App = () => {
  const [number, setNumber] = useState(0);
  const [text, setText] = useState("");

  const increaseNumber = () => {
    setNumber((prevState) => prevState + 1);
  };

  const decreaseNumber = () => {
    setNumber((prevState) => prevState - 1);
  };

  const onChangeTextHandler=(e)=>{
    setText(e.target.value);
  }

  return (
    <div className="App">
      <div>
        <button onClick={increaseNumber}>+</button>
        <button onClick={decreaseNumber}>-</button>
        <input
          type="text"
          placeholder="Last Name"
          onChange={onChangeTextHandler}
        />
      </div>
      <ShowState number={number} text={text} />
    </div>
  );
};

export default App;

이제 App으로부터 number과 text를 내려받는 ShowState 컴포넌트를 만들어보겠습니다.

//ShowState.js

import React from "react";
import "./styles.css";

const getNumber = (number) => {
  console.log("숫자가 변동되었습니다.");
  return number;
};

const getText = (text) => {
  console.log("글자가 변동되었습니다.");
  return text;
};

const ShowState = ({ number, text }) => {
  const showNumber = getNumber(number);
  const showText = getText(text);

  return (
    <div className="info-wrapper">
      {showNumber} <br />
      {showText}
    </div>
  );
};

export default ShowState;

코드 쉽게 이해되시죠??
이제 해당 페이지에서 +,- 버튼을 눌러 number 값을 바꾸어보기도하고 input창에서 text를 변경시켜보기도 해볼까요?.

그렇게 하시면 아마 이러한 console을 보실겁니다.

숫자가 변동되었습니다.
글자가 변동되었습니다.

어떤게 문제인지 아시겠죠? 저희는 숫자만 변경하였는데도 위의 두개의 문장이 console에 뜨는 것을 볼 수 있습니다.
잘 모르시는 분이봐도 이건 분명 문제가 있다고 생각할겁니다.

변경하고자 하는 state에 해당되지 않는 함수도 덩달아 실행된다니.. 이거 너무 비효율적이고 낭비아닌가요?
우리는 이럴 때 useMemo를 사용합니다!

ShowState 컴포넌트 내에서 useMemo를 사용해보겠습니다.

const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);

react 공식홈페이지에 나와있는대로 적용하면 됩니다. 여기서 우리가 memoization 할 값은 showNumbershowText임으로 그대로 적용시켜주겠습니다.

//ShowState.js

import React,{useMemo} from "react";
import "./styles.css";

const getNumber = (number) => {
  console.log("숫자가 변동되었습니다.");
  return number;
};

const getText = (text) => {
  console.log("글자가 변동되었습니다.");
  return text;
};

const ShowState = ({ number, text }) => {
  const showNumber = useMemo(()=>getNumber(number),[number]);
  const showText = useMemo(()=>getText(text),[text]);

  return (
    <div className="info-wrapper">
      {showNumber} <br />
      {showText}
    </div>
  );
};

export default ShowState;

적용방법이 상당히 간단합니다. 이제 아까처럼 +,- 버튼을 눌러보거나 input 창에 글을 입력해볼까요?

어떤가요?
숫자가 변경될 때는 '숫자가 변동되었습니다.' 라는 console만
글자가 변경될 때는 '글자가 변동되었습니다.' 라는 console만 뜨죠??

이렇게 useMemo의 사용법에 대해 알아보았습니다.
물론 현재 제가 예시로 작성한 코드에서 useMemo의 사용 유무는 성능에 큰 영향을 주진 않을겁니다. 굉장히 간단한 계산들로만 이루어져 있기 때문이죠.

react 공홈에서 예시로 든 코드를 보면 computeExpensiveValue라는 함수가 들어가있죠? 이처럼 memoization되는 값의 재계산 로직이 expensive한 경우, 즉 복잡한 계산일 경우에 useMemo를 사용하는 것이 추천되고 이런 경우에는 성능상 큰 이점으로 작용한답니다.

마무리

이번 포스팅에서는 useMemo에 대해 알아보았는데요.
아마 내일은 useCallback을 설명한 뒤에 useMemo와 useCallback을 비교해보는 식의 포스팅을 진행할 것 같습니다.
읽어주셔서 감사합니다.

profile
김용성입니다.

5개의 댓글

comment-user-thumbnail
2021년 4월 16일

예시가 이해하기 쉽게 나와있어서 좋았어요~~!!! 감사합니다 :)
별건 아닌데, 마크다운 작성하실때 jsx로 하시면 좀 더 가독성 좋게 코드가 읽힐 것 같아요! (다 흑백이라 조금 잘 안읽히는 부분이 있었어요)

1개의 답글
comment-user-thumbnail
2021년 5월 3일

함수형 컴포넌트는 JSX를 반환하는 함수일 뿐이다.. 명심하겠습니다

답글 달기
comment-user-thumbnail
2021년 9월 14일

좋은글 감사합니다~

답글 달기
comment-user-thumbnail
2023년 4월 3일

안녕하세요 좋은 글 감사합니다! 개인 공부 중 많은 도움이 되었는데 혹시 출처를 남기고 제 벨로그에 참고해서 정리해도 괜찮을까요...?!

답글 달기