3 분 소요

Memoization 이란?

Memoization은 프로그래밍 기법 중 하나로 기존에 수행한 연산의 결과값을 메모리에 저장해놓고 필요할 때 재사용하여 계산의 반복수행을 하지 않는 것입니다. 이런 기법을 사용하게 되면 중복 연산을 피할 수 있기 때문에 프로그램 실행 속도가 빨라지게 됩니다.

useMemo() 란?

리액트에서 함수형 컴포넌트는 렌더링 -> Component 함수 호출 -> 모든 내부 변수 초기화의 순서를 거치게 됩니다. 이 때 무거운 연산을 하는 어떤 함수를 리렌더링이 될 때 마다 반복적으로 호출하게 된다면 효율성이 굉장히 떨어질 수 있는데요. 리액트에서 useMemo를 사용하면 렌더링 -> Component 함수 호출 -> Memoize된 함수 재사용의 순서를 거치게 됩니다. 이는 처음 계산된 결과값이 메모리에 저장되어서 컴포넌트가 리렌더링 될 때 계산된 결과값을 메모리에서 꺼내와서 재사용할 수 있는 것으로, 불필요한 연산을 없애고 성능을 더욱 최적화 할 수 있게 하는 것입니다. useMemo를 사용하게 되면 Memoization용 메모리가 필요하기 때문에 남용하는 것은 좋지 않습니다.

useMemo 사용 방법

  • import
1
import { useMemo } from "react";

리액트에서 useMemo를 사용하기 위해서는 가장 먼저 위와 같이 react에서 useMemo를 import 해야합니다.

  • 기본 형태
1
2
3
4
5
// 첫 번째 인자 콜백함수
// 두 번째 인자 의존성배열
const value = useMemo(() => {
  return a();
}, [b]);

useMemo의 기본 형태는 위와 같습니다.
첫 번째 인자로는 콜백함수를, 두 번째로 인자로는 의존성배열을 받는데요. 두 번째 인자로 들어가는 배열 요소 값이 업데이트 될 때만 콜백함수를 다시 호출해서 연산하고, 값이 업데이트 되지 않으면 이전에 연산했던 값을 재사용하게 됩니다.

  • useMemo를 사용하지 않았을 때
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
29
30
31
32
33
34
35
36
37
38
39
import React, { useState } from "react";

const Practice = () => {
  const [list, setList] = useState([]);
  const [number, setNumber] = useState("");

  const calculate = () => {
    console.log("계산중 입니다!");
    if (list.length === 0) return 0;
    const sum = list.reduce((a, b) => a + b);
    return sum;
  };
  const onChange = (e) => {
    setNumber(e.target.value);
  };

  const onInsert = () => {
    const nextList = list.concat(parseInt(number));
    setList(nextList);
    setNumber("");
  };

  return (
    <div>
      <input value={number} onChange={onChange} />
      <button onClick={onInsert}>등록</button>
      <ul>
        {list.map((value, index) => (
          <li key={index}>{value}</li>
        ))}
      </ul>
      <div>
        <strong>합계 :</strong> {calculate()}
      </div>
    </div>
  );
};

export default Practice;

위 코드는 useMemo를 사용하지 않고 만든 코드입니다. 이런 경우에는 최초, 글자 입력 시, 버튼 클릭 시에 모두 “계산중 입니다!” 라는 메시지가 콘솔에 찍히게 됩니다.

  • useMemo를 사용했을 때
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
29
30
31
32
33
34
35
36
37
38
39
40
41
import React, { useState, useMemo } from "react";

const Practice = () => {
  const [list, setList] = useState([]);
  const [number, setNumber] = useState("");

  const calculate = useMemo(() => {
    console.log("계산중 입니다!");
    if (list.length === 0) return 0;
    const sum = list.reduce((a, b) => a + b);
    return sum;
  }, [list]);

  const onChange = (e) => {
    setNumber(e.target.value);
  };

  const onInsert = () => {
    const nextList = list.concat(parseInt(number));
    setList(nextList);
    setNumber("");
  };

  return (
    <div>
      <input value={number} onChange={onChange} />
      <button onClick={onInsert}>등록</button>
      <ul>
        {list.map((value, index) => (
          <li key={index}>{value}</li>
        ))}
      </ul>
      <div>
        <strong>합계 :</strong> {calculate}
        {/* 여기서 calculate는 useMemo를 사용했기 때문에 값을 반환합니다 */}
      </div>
    </div>
  );
};

export default Practice;

위와 같이 useMemo를 사용한 경우에는 list가 업데이트 될 때만 렌더링하게 됩니다.

Today I Learned

오늘은 리액트 Hooks 중에서 useMemo에 대해 공부했습니다. useMemo를 남용하면 메모리가 낭비되기도 하고, 평소 사용환경에서는 useEffect를 사용하여 비동기로 처리하는 경우가 많을 듯 하지만 useMemo는 알아놓으면 좋은 Hooks인 것 같습니다. 다음 번에는 useMemo와 유사한 useCallback에 대해 공부해보고 차이점은 무엇인지 알아봐야겠습니다 :)

🔔포스팅 공지
개인 공부 기록용 블로그 입니다.
잘못된 부분이 있을 시 메일이나 댓글로 지적해주시면 감사드리겠습니다 :)

댓글남기기