컴포넌트 최적화에 사용되는 대표적인 훅은 useMemo와 useCallback이 있다. 오늘은 그 중에서 useMemo에 대해서 공부해보려고 한다.
useMemo에서 memo라는 말은 Memoization(메모이제이션)을 뜻하는 말이다.
동일한 값을 리턴하는 함수를 반복적으로 호출을 해야 된다면 맨 처음 호출을 할 때, 값을 메모리에 저장하여 필요할 때마다 메모리에서 꺼내 재사용하는 기법이다.
🙋🏻♂️ 간단하게 말해서 자주 필요한 값을 맨 처음 계산할 때, 캐싱을 해둬서, 필요할 때마다 다시 계산하는 것이 아닌, 캐시에서 꺼내어 사용한다는 뜻이다.
useMemo도 무분별하게 사용하게 된다면, 값을 메모리에 저장하는 것이므로 불필요한 값으로 메모리를 소비하여, 성능이 악화 될 수도 있다!!
import { useState } from "react";
export default function UseMemoPracticePage() {
const [hardNumber, setHardNumber] = useState(1);
const [easyNumber, setEasyNumber] = useState(1);
const onChangeHardNumber = (event) => {
setHardNumber(event.target.value);
};
const onChangeEasyNumber = (event) => {
setEasyNumber(event.target.value);
};
const hardCalculate = (inputNumber) => {
console.log("무거운 작업 함수");
// 무거운 작업이라는 가정으로 의미 없는 for문 추가
for (let i = 0; i < 999999999; i++) {}
return Number(inputNumber) + 10000;
};
const easyCalculate = (inputNumber) => {
console.log("가벼운 작업 함수");
return Number(inputNumber) + 1;
};
const hardResult = hardCalculate(hardNumber);
const easyResult = easyCalculate(easyNumber);
return (
<div>
<p>useMemoPractice</p>
<hr />
<h3>무거운 계산</h3>
<input type={"number"} value={hardNumber} onChange={onChangeHardNumber} />
<span> + 10000 = {hardResult}</span>
<br />
<h3>가벼운 계산</h3>
<input type={"number"} value={easyNumber} onChange={onChangeEasyNumber} />
<span> + 1 = {easyResult}</span>
</div>
);
}
🙋🏻♂️ 무거운 계산을 하는 함수와 가벼운 계산을 함수를 만들었다. 하지만 이 코드에는 문제가 존재하는데, 바로 함수형 컴포넌트이기 때문에 무거운 함수가 계속 초기화가 되어서(의미없는 for루프가 실행 됨) 가벼운 계산 함수를 사용해도 딜레이가 걸리는 것이다. 이러한 이유 때문에 useMemo를 사용하는 것이다.
// const hardResult = hardCalculate(hardNumber);
const hardResult = useMemo(() => {
return hardCalculate(hardNumber);
}, [hardNumber]);
🙋🏻♂️ hardResult를 useMemo를 사용하고 dep으로 hardNumber를 주게 되면, hardNumber의 값이 바뀔 때만 콜백을 해주게 된다.
useMemo
는 '값'을 메모이제이션하여 값을 반환하지만,
useCallback
은 '함수'를 메모이제이션하여 함수를 반환한다.
useCallback
으로는 컴포넌트가 렌더링 될 때마다 내부적으로 사용된 함수가 새롭게 생성되는 경우, 자식 컴포넌트에 Prop으로 새로 생성된 함수가 넘겨지게 되면 불필요한 리렌더링이 일어날 수 있는 경우에, 방지 할 수 있다.