기본적으로 react는 부모 컴포넌트로 부터 받는 state, props가 변동될 경우 리렌더링 된다.
하지만 여기에는 분명한 문제가 존재한다.
예를 들어 state, props가 여러가지 일 때
state1, state2, state3이 존재하는 상태에서 state1을 변경시켰는데도 state2, state3도 다시 계산된다면 이것이 과연 좋은 리렌더링 인가?
useMemo
와 useCallback
은 이러한 고민을 가진 개발자들을 위해 탄생했다고 봐도 무방하다.
간단한 예제를 살펴보자.
파일 구성은 App.js
와 ShowState.js
로 구성되어 있다.
// App.js
import React, { useState } from "react";
import ShowState from "./ShowState";
const App = () => {
const [number, setNumber] = useState(0);
const [text, setText] = useState("");
const increaseNumber = () => {
setNumber((prev) => prev + 1);
};
const decreaseNumber = () => {
setNumber((prev) => prev - 1);
};
const onChangeTextHandler = (e) => {
setText(e.target.value);
};
return (
<div className="App">
<div>
<button onClick={increaseNumber}>+</button>
<button onClick={decreaseNumber}>-</button>
<input
type="text"
placeholder="Last Name"
onChange={onChangeTextHandler}
/>
</div>
<ShowState number={number} text={text} />
</div>
);
};
export default App;
다음은 App으로부터 number와 text를 내려받는 ShowState 컴포넌트 이다.
import React from "react";
const getNumber = (number) => {
console.log("숫자가 변동되었습니다.");
return number;
};
const getText = (text) => {
console.log("글자가 변동되었습니다.");
return text;
};
const ShowState = ({ number, text }) => {
const showNumber = getNumber(number);
const showText = getText(text);
return (
<div className="info-wrapper">
{showNumber} <br />
{showText}
</div>
);
};
export default ShowState;
숫자만 변경하였는데도 위 두 개의 문장이 콘솔에 출력되는 것을 볼 수 있다.
변경하고자 하는 state에 해당되지 않는 함수도 덩달아 실행되니 비효율적이고 낭비라고 생각된다.
이럴 때 useMemo를 사용한다.
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b])
// ShowState.js
import React, { useMemo } from "react";
const getNumber = (number) => {
console.log("숫자가 변동되었습니다.");
return number;
};
const getText = (text) => {
console.log("글자가 변동되었습니다.");
return text;
};
const ShowState = ({ number, text }) => {
const showNumber = useMemo(() => getNumber(number), [number]);
const showText = useMemo(() => getText(text), [text]);
return (
<div className="info-wrapper">
{showNumber} <br />
{showText}
</div>
);
};
export default ShowState;
숫자가 변경될 때는 '숫자가 변동되었습니다.' 라는 출력
글자가 변경될 때는 '글자가 변동되었습니다.' 라는 출력이 나오는 걸 볼 수 있다.
이처럼 memoization 되는 값의 재계산 로직이 expensive한 경우, 즉 복잡한 계산일 경우에 useMemo를 사용하는 것이 추천되고 이런 경우에는 성능상 큰 이점으로 작용한다.