240819 React 메모이제이션 - useMemo

신한별·2024년 8월 17일

💪 매일 기록

목록 보기
59/97

04. useMemo

useMemo를 통해 값을 memoization(기.억) 하는 방법을 알아보자 레츠고

(1) useMemo?

memoization

동일한 값을 반환하는 함수를 계속 호출해야 한다면? 필요없는 랜더링이 발생한다.
💢 해결 방법 ? 맨 처음 해당 값을 반환 시 그 값을 메모리에 저장한다.
캐싱 : 필요할 때 마다 함수를 호출하고 새로 계산하는 것이 아니라 이미 저장한 값을 꺼내와서 씀
특히 복잡한 계산 결과값을 memoization 할때 많이 사용

(2) 사용방법

// as-is
const value = 반환할_함수();

// to-be
const value = useMemo(()=> {
	return 반환할_함수()
}, [dependencyArray]);

(3) useMemo 적용해보기 1

HeavyComponent 안에서 const value = heavyWork() 를 통해 value를 세팅해주고 있다.
만약 heavyWork가 무거운 작업이라면, 다른 state가 바뀔 때 마다 계속해서 호출이 될 것이다.
하지만 useMemo()로 감싸준다면 그럴 일 없을 것이다.

App.jsx

import "./App.css";
import HeavyComponent from "./components/HeavyComponent";

function App() {
 const navStyleObj = {
   backgroundColor: "yellow",
   marginBottom: "30px",
 };

 const footerStyleObj = {
   backgroundColor: "green",
   marginTop: "30px",
 };

 return (
   <>
     <nav style={navStyleObj}>네비게이션 바</nav>
     <HeavyComponent />
     <footer style={footerStyleObj}>푸터 영역이에요</footer>
   </>
 );
}

export default App;

components > HeavyComponent.jsx

import React, { useState, useMemo } from "react";

function HeavyButton() {
  const [count, setCount] = useState(0);

  const heavyWork = () => {
    for (let i = 0; i < 1000000000; i++) {}
    return 100;
  };

	// CASE 1 : useMemo를 사용하지 않았을 때
  const value = heavyWork();

	// CASE 2 : useMemo를 사용했을 때
  // const value = useMemo(() => heavyWork(), []);

  return (
    <>
      <p>나는 {value}을 가져오는 엄청 무거운 작업을 하는 컴포넌트야!</p>
      <button
        onClick={() => {
          setCount(count + 1);
        }}
      >
        누르면 아래 count가 올라가요!
      </button>
      <br />
      {count}
    </>
  );
}

export default HeavyButton;

한국인을 화나게 만드는 속도

(4) useMemo 적용해보기 2

다음과 같은 코드가 있따면?

import React, { useEffect, useState } from "react";

function ObjectComponent() {
  const [isAlive, setIsAlive] = useState(true);
  const [uselessCount, setUselessCount] = useState(0);

  const me = {
    name: "Ted Chang",
    age: 21,
    isAlive: isAlive ? "생존" : "사망",
  };

  useEffect(() => {
    console.log("생존여부가 바뀔 때만 호출해주세요!");
  }, [me]);

  return (
    <>
      <div>
        내 이름은 {me.name}이구, 나이는 {me.age}야!
      </div>
      <br />
      <div>
        <button
          onClick={() => {
            setIsAlive(!isAlive);
          }}
        >
          누르면 살았다가 죽었다가 해요
        </button>
        <br />
        생존여부 : {me.isAlive}
      </div>
      <hr />
      필요없는 숫자 영역이에요!
      <br />
      {uselessCount}
      <br />
      <button
        onClick={() => {
          setUselessCount(uselessCount + 1);
        }}
      >
        누르면 숫자가 올라가요
      </button>
    </>
  );
}

export default ObjectComponent;
  • useEffect를 이용해 me의 정보가 바뀌었을 때만 발동하게 dependency array을 넣었으나
    뜬금없이 count 증가 버튼을 누르면 계속 콘솔 로그가 찍힌다. 😵

⚠ 불변성 때문이야

버튼 선택 ▶ uselessCount state 변경 ▶ 리랜더링 ▶ 컴포넌트 함수 새로 호출
▶ me 객체도 재할당(다른 메모리 주소값 할당)
▶ useEffect의 dependency array 에 의해 me 객체가 바뀌었는지 확인하려고 했더니
▶ 모양은 같은데 주소가 다르다!
▶▶ 리액트 : 어? me 바꼈네? ㅇㅋ useEffect 내부로직 부를게

이것도 useMemo로 해결 가능

const me = useMemo(() => {
  return {
    name: "Ted Chang",
    age: 21,
    isAlive: isAlive ? "생존" : "사망",
  };
}, [isAlive]);

useMemo()만 이렇게 해주면 uselessCount가 아무리 많이 증가해도 영향 x

추가 설명

// 이건 일치해요
const a = 1;
const b = 1;

console.log(a === b); // true

// 하지만 이건 달라요
const me = {
  name: "ted chang",
  age: 21,
};

const you = {
  name: "ted chang",
  age: 21,
};

console.log(me === you); // false

(5) 주의사항

useMemo 을 남발하면 메모리가 터져서 오히려 성능이 나빠질 수 있다! 조심하자!

0개의 댓글