useMemo는 react에서 렌더링 최적화를 위해 사용되는 react hooks이다.
useMemo를 보기 전에 알고리즘의 Memoization에 대해 살펴볼 필요가 있는데
Memoization
Memoization은 기존에 수행했던 연산의 결과값을 다른 곳에 저장해두고 동일한 입력 값이 들어오면 저장되어 있던 값을 반환해주는 프로그래밍 기법이다. Memoization을 잘 사용하면 불필요한 연산을 피할 수 있다.
이 Memoization을 리액트에 적용하여 리액트 애플리케이션의 성능을 최적화하기 위해 useMemo가 사용된다.
useMemo
react에서는 상위 컴포넌트로부터 상속 받은 state, props가 업데이트되는 경우 리렌더링이 일어난다.
하지만 이 때 state, prop의 수가 여러 개라면 하나의 state, props가 변경되더라도 컴포넌트 내의 모든 state,props에서 업데이트가 일어나 업데이트가 일어나지 않는 곳에서도 불필요하게 업데이트된다.
useMemo의 사용법
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
computeExpensiveValue(a, b)라는 ‘생성’ 함수와 [a, b]라는 종속성 배열을 전달하는데
종속성 배열 중 하나가 변경된 경우에만 메모된 값을 다시 계산 즉, 업데이트가 일어난다.
종속성 배열을 생략한 경우에는 렌더링할 때마다 새 값이 계산된다.
app.jsx와 test.jsx로 구성된 아래 예시를 살펴보자면,
without useMemo
// app.jsx
import React, { useState } from "react";
import Test from "./test";
const App = () => {
const [num, setNum] = useState(0);
const [text, setText] = useState("");
const increaseNum = () => {
setNumber((prevNum) => prevNum + 1);
};
const decreaseNum = () => {
setNumber((prevNum) => prevNum - 1);
};
const textHandler = (event) => {
setText(e.target.value);
};
return (
<div>
<div>
<button onClick={increaseNum}>+</button>
****<button onClick={decreaseNum}>-</button>
<input type="text" onChange={textHandler} />
</div>
<Test num={num} text={text} />
</div>
);
};
export default App;
// test.jsx
import React from "react";
const changeText = (text) => {
console.log("text 업데이트");
return text;
};
const changeNum = (num) => {
console.log("num 업데이트");
return num;
};
const Test = ({ num, text }) => {
const viewNum = changeNum(number);
const viewText = changeText(text);
return (
<div>
{viewNum} <br />
{viewText}
</div>
);
};
export default Test;
위의 구조로 구성된 컴포넌트에서 button을 누르거나 input에 text를 입력했을 때 콘솔을 확인해보면
changeText와 changeNum함수 둘 다 실행되는 것을 볼 수 있다. 이 경우 업데이트가 일어나지 않아도 될 함수에서 업데이트가 일어나는 것이다.
with useMemo
// test.jsx
import React, { useMemo } from "react";
const changeText = (text) => {
console.log("text 업데이트");
return text;
};
const changeNum = (num) => {
console.log("num 업데이트");
return num;
};
const Test = ({ num, text }) => {
const viewNum = useMemo(() => changeNum(num), [num]);
const viewText = useMemo(() => changeText(text), [text]);
return (
<div>
{viewNum} <br />
{viewText}
</div>
);
};
export default Test;
useMemo를 적용하여 버튼과 input에 변화를 주었을 경우 변화된 숫자나 텍스트에서만 콘솔이 찍히는 것을 확인할 수 있다. 이처럼 불필요한 업데이트를 피하고 성능을 업그레이드하기 위해 useMemo가 사용된다.
하지만
useMemo를 모든 곳에 사용하게 된다면 그만큼 컴포넌트가 비대해지고, useMemo가 적용된 곳은 가바지 컬렉션(garbage collection)에서 제외가 되기 때문에 메모리도 더 사용하게 된다.
이러한 이유로 useMemo는 사용이 필요한 곳에서만 사용해야한다.