[React]성능 최적화의 useMemo, useCallback

Grace·2021년 7월 27일
1

react

목록 보기
3/6
post-thumbnail
post-custom-banner

그렇기 때문에 배워야해..

성능최적화를 위한 도구

참고한 포스팅의 글 첫머리에 지극히 공감을 하게 되었다.

이제 useStateuseEffect에 완전히 익숙해졌다고 느꼈는데, 컴포넌트 내에서 저 두 개의 hook 만으로도 props나 state를 다루는 로직에 관련된 기본적인 기능을 모두 구현할 수 있기 때문에 굳이 useMemouseCallback 을 사용할 필요를 느끼지 못했다.

게다가 나는 완전히는 더더욱 아니라서 최적화를 생각해보기엔 어려운 부분이 있었다.
하지만 쓰지도 않으면서 부르기만 하는건, 프로그램 입장에서도 좋지 않겠단(?)
생각에 최적화에 대한 생각도 해보기로 했다.

그럼에도 불구하고 사용해 볼 필요를 못 느낀다는 것이 그 기술의 장단점을 파악해서 결정한 것이 아니라 “단지 익숙하지 않은 기술을 배우지 않으려고 하는 나의 좁은 마음 때문” 이라는 생각이 스쳐지나갔다.

네, 바로 접니다...
그래서 이번 기회로 기술의 장단점을 정리하면서 사용법을 익혀두기로 했다.


💡 먼저 알고 있어야 하는 부분

  • '컴포넌트의 렌더링' 이란 어딘가에서 함수(컴포넌트)를 호출했기에 실행되는 것을 말한다.
  • 함수(컴포넌트)가 실행되면 내부의 로직들 또한 매번 다시 선언되어 사용된다.
  • 컴포넌트는 자신의 state가 변하거나 부모에게서 받는 props에 변동이 일어나면 렌더링이 일어난다.
  • 리액트 컴포넌트는 기본적으로 부모컴포넌트가 리렌더링되면 바뀌는 내용이 없더라도 자식 컴포넌트 또한 리렌더링이 된다.
  • 리액트는 Virtual DOM에 렌더링을 시키는 구조이기 때문에, 실제 DOM에는 변경되는 부분만 반영되지만 Virtual DOM에는 모든걸 다시 렌더링한다.
  • 그렇기 때문에 기존 기능은 건드리지 않되, Virtual DOM에 사용되는 비용을 줄이는 데에 useMemo, useCallback를 사용한다.

useMemo

말 그대로 이미 연산된 메모해둠으로서 재사용하는 hook이다.

공식문서에 나와있는 사용법이다. (공식문서 보는 습관을 기르도록 하자)
useMemo를 사용하게 되면, 모든 랜더링시의 고비용 계산을 방지하게 해준다.

아래 코드를 예로 들어보자면,

import React from "react";

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

이 경우에는 ComponentRender함수가 랜더링 될 때마다
valueProp1 함수 또한 계속 랜더링 될 것이다.
그렇기에 변경되는 props만을 감지해서 다시 계산할 수 있도록
useMemo를 사용해서 성능최적화를 해보자.

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>
    </>
  );
};

이제 valueProp1 함수는 prop1이 변경될때만 랜더링된다.
만약 prop2가 변경되어 ComponentRender함수가 리랜더링 될 경우엔
prop1은 마지막으로 계산된 값을 사용하게 된다.

useCallback

useMemo가 계산된 '값'을 재사용한다면, useCallback은 계산된 함수를 기억하고 재사용한다.

코드로 예를 들어보자면,

import React, { useState } from 'react';

const ComponentRender = ({ cb1, cb2 }) => {
  const [state, setState] = useState(...);
  const expensiveFunction = () => {
    // 에너지가 많이 소모되는 계산이 일어남
    ...
    setState(...);
    cb1();
  };
  return (
    <button onClick={expensiveFunction} />
  );
};

이 경우엔 useMemo와 동일하게,
컴포넌트의 랜더링이 일어나게 되면, 그 안에 있는 함수까지
다시 랜더링이 일어나게 된다.
그렇기 때문에 호출되지 않은 함수에 대해서는
계산의 낭비가 없도록 useCallback을 사용한다.

import React, { useState } from 'react';

const ComponentRender = ({ cb1, cb2 }) => {
  const [state, setState] = useState(...);
  const expensiveFunction = useCallback(() => {
    // 에너지가 많이 소모되는 계산이 일어남
    ...
    setState(...);
    cb1();
  }, [cb1]);
  return (
    <button onClick={expensiveFunction} />
  );
};

이렇게 deps까지 설정해주게 되면,
cb1함수에 대해서는, 변경이 일어나지 않는 한
쓸데없이 호출되지 않게 된다.

참고하였습니다 :)

profile
쉽게 사는건 재미가 없더군요, 새로 시작합니다🤓
post-custom-banner

0개의 댓글