티스토리 뷰

Client/React.js

[React] useMemo

무화과(Fig) 2023. 8. 18. 21:55


목차

 

1. useMemo

2. useMemo 구조

3. useMemo 예제1

3. useMemo 예제2


 

 

 

 

컴포넌트 최적화를 위해 사용되는 대표적인 hook은 useMemo와 useCallback이다.

오늘은  중에서useMemo에 대해 공부해보려고 한다.

 

 

1. useMemo


useMemo는 리액트에서 컴포넌트의 성능을 최적화 하는데 사용되는 훅이다.

 

useMemo에서 memo는 memoization을 뜻하는데 이는 그대로 해석하면 ‘메모리에 넣기’라는 의미이며 컴퓨터 프로그램이 동일한 계산을 반복해야 할 때, 이전에 계산한 값을 메모리에 저장함으로써 동일한 계산의 반복 수행을 제거하여 프로그램 실행 속도를 빠르게 하는 기술이다.

 

쉽게 말해 동일한 값을 반환하는 함수를 반복적으로 호출해야한다면 처음 값을 계산할 때 해당 값을 메모리에 저장해 필요할 때마다 다시 계산하지 않고 메모리에서 꺼내서 재사용하는 것이다.

 

리액트에서 함수형 컴포넌트는

 

1. 렌더링

2. 컴포넌트 함수 호출

3. 모든 내부 변수 초기화의 순서를 거친다.

 

 

다음 예제를 통해 더 자세히 알아보자.

function Component() {
    const value = calculate();
    return <div>{value}</div> 
}

 

위 코드를 보면 컴포넌트가 렌더링 될 때마다 value라는 변수가 초기화된다.
즉, 렌더링 될 때마다 calculate 함수가 불필요하게 재호출되기 때문에 만약 calculate가 무겁고 복잡한 함수라면 매우 비효율적일 것이다.

이것을 해결하기 위해 useMemo 훅을 사용하면 된다.

 

useMemo를 사용하면 렌더링 => 컴포넌트 함수 호출 => memoize된 함수 재사용하는 순서를 거치는데 이렇게 되면 calculate 함수를 반복적으로 실행할 필요가 없게 된다.


useMemo는 앞서 말했듯이 처음에 계산된 값을 메모리에 저장해 컴포넌트가 계속 렌더링되어도 calculate를 다시 호출하지 않고 메모리에 저장되어있는 계산된 값을 가져와 재사용할 수 있게 해준다.

 

 

 

 

2. useMemo 구조


const value = useMemo(() => {
    return calculate();
},[item])

useMemo는 useEffect처럼 첫 번째 인자로 콜백 함수, 두 번째 인자로 의존성 배열(dependancyArray)을 받는다.

 

의존성 배열 안에 있는 값이 업데이트 될 때에만 콜백 함수를 다시 호출하여 메모리에 저장된 값을 업데이트 해준다.

만약 빈 배열을 넣는다면 useEffect와 마찬가지로 마운트 될 때에만 값을 계산하고 그 이후론 계속 memoization된 값을 꺼내와 사용한다.

 

 

 

 

 

3. useMemo 예제1


import { useState } from "react";
 
const hardCalculate = (number) => {
  console.log("어려운 계산!");
  for (let i = 0; i < 99999999; i++) {} // 생각하는 시간
  return number + 10000;
};

const easyCalculate = (number) => {
  console.log("쉬운 계산!");
  return number + 1;
};

function App() {
  const [hardNumber, setHardNumber] = useState(1);
  const [easyNumber, setEasyNumber] = useState(1);

  const hardSum = hardCalculate(hardNumber);
  const easySum = easyCalculate(easyNumber);

  return (
    <div>
      <h3>어려운 계산기</h3>
      <input
        type="number"
        value={hardNumber}
        onChange={(e) => setHardNumber(parseInt(e.target.value))}
      />
      <span> + 10000 = {hardSum}</span>
      
      
      <h3>쉬운 계산기</h3>
      <input
        type="number"
        value={easyNumber}
        onChange={(e) => setEasyNumber(parseInt(e.target.value))}
      />
      <span> + 1 = {easySum}</span>
    </div>
  );
}

export default App;

위 예제에 어려운 계산기와 쉬운 계산기가 있다.

 

어려운 계산기는 반복문을 99999999번 돌리고 값을 반환하기 때문에 숫자를 변경하면 누르면 1초 정도의 딜레이를 거친 후 값이 변경된다.

문제는 쉬운 계산기의 값을 변경해도 1초 정도의 딜레이를 거친 후 값이 변경된다.

 

그 이유는 쉬운 계산기의 input값을 변경하면 함수형 컴포넌트인 App이 리렌더링되는데 이 때 위에서 말했듯 내부의 변수들이 초기화되기 때문에 hardCalculate가 다시 실행되기 때문이다.

 

그렇다면 이제 useMemo를 통해 이를 방지해보자.

 

 

 

const hardSum = useMemo(() => {
    return hardCalculate(hardNumber);
  }, [hardNumber]);
  const easySum = easyCalculate(easyNumber);

이처럼 useMemo의 첫 번째 인자로 콜백 함수를 넣고, 의존성 배열 안에 hardNumber를 넣어 hardNumber 값이 변경될 때에만 콜백함수가 실행되게 하면 된다.

 

하지만 리액트에서 useMemo가 정말 빛을 발하는 상황은 따로있다.
다음 예제를 통해 함께 살펴보자.

 

 

 

 

 

4. useMemo 예제2


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

function App() {
  const [number, setNumber] = useState(1);
  const [isKorea, setIsKorea] = useState(true);

  // 1번 location
  const location = {
    country: isKorea ? "한국" : "일본"
  };

  // 2번 location
  // const location = useMemo(() => {
  //   return {
  //     country: isKorea ? '한국' : '일본'
  //   }
  // }, [isKorea])

  useEffect(() => {
    console.log("useEffect 호출!");
  }, [location]);

  return (
    <header className="App-header">
      <h2>하루에 몇 끼 먹어요?</h2>
      <input
        type="number"
        value={number}
        onChange={(e) => setNumber(e.target.value)}
      />
      <hr />

      <h2>내가 있는 나라는?</h2>
      <p>나라: {location.country}</p>
      <button onClick={() => setIsKorea(!isKorea)}>Update</button>
    </header>
  );
}

export default App;

 

useEffect의 의존성 배열에 location을 넣었는데 number state를 변경해도 useEffect가 실행된다.

 

그 이유는 자바스크립트에서 객체는 원시 타입과는 다르게 값이 저장될 때 주소 값으로 저장되기 때문이다.

그렇기 때문에 리액트에선 number state가 바뀌면 App 컴포넌트가 재호출되면서 location의 주소값이 변경이 되었기 때문에 location이 변경이 되었다고 인식을 한다.

 

여기서도 useMemo 훅을 통해 이를 방지할 수 있다.

위 식에서 주석을 통해 1번 location과 2번 location을 구분해놨으니 두개를 번갈아가며 사용해보면 어떤 차이가 있는지 확인할 수 있다.

'Client > React.js' 카테고리의 다른 글

[React] Redux 이해하기  (0) 2023.08.28
[React] useCallback  (0) 2023.08.25
[React] 1. React-app 설치방법  (0) 2023.08.21
[React] useReducer  (0) 2023.08.14
[React] useEffect (컴포넌트의 Lifecycle, clean up function)  (0) 2022.08.17
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/02   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28
글 보관함