
const cachedValue = useMemo(() => {
calculateValue...
}, [dependencies])
useMemo는 리렌더링 사이의 계산 결과를 캐시할 수 있는 React 훅이다.
(캐시(Cache) : 용량이 작고 빠른 메모리로, 주 기억 장치에 매법 접근하는 것을 피하고자 최근에 사용된 정보를 저장하는 임시 장소)
calculateValue : memoization해줄 값을 계산해서 리턴해줄 값을 계산하는 콜백함수가 들어가는 부분.
dependencies : 의존성 배열. 배열안의 요소의 값이 업데이트 될 때만 콜백함수를 다시 호출하여 memoization된 값을 업데이트 해서 다시 memoization을 해줌.
만약 빈 배열이면 맨 처음 컴포넌트가 마운트되었을 때만 값을 계산하고 이후엔 항상 memoization된 값을 꺼내와서 사용한다.
함수형 컴포넌트는 '함수'이다.
그래서 함수 호출을 하면 모든 내부 변수가 초기화가 된다.
이 과정에서 컴포넌트가 반복적으로 렌더링 되어도 이전에 Memoize 된 값을 재사용 할 수 있게 해준다.
자주 사용하면 안되는 이유는 값을 재사용하기 위해 메모리를 소비하여 저장해주는 방식이라 불필요한 값까지 memoize하면 오히려 성능에 악화된다.
즉, 다른 값 변화엔 렌더링 영향을 받지 않고 memoization된 값이 변했을 때만 렌더링 영향을 받을 수 있게 해준다.
function UseMemoDeepening() {
const [number, setNumber] = useState(0);
const [isKorea, setIsKorea] = useState(true);
// const location = isKorea ? "한국" : "외국";
// ===> 원시 타입
const location = useMemo(() => {
return {
country: isKorea ? "한국" : "외국",
};
}, [isKorea]);
// ===> 객체 타입
useEffect(() => {
console.log("useEffact 호출");
}, [location]);
return (
<div>
<div>
<h2>하루에 몇끼를 드세요?</h2>
<input
type="number"
value={number}
onChange={(e) => setNumber(e.target.value)}
/>
</div>
<br />
<hr />
<br />
<div>
<h2>어느 나라에 있어요?</h2>
<p>나라 : {location.country}</p>
<button onClick={() => setIsKorea(!isKorea)}>
비행기를 타야겠군요.
</button>
</div>
</div>
);
}
위 예제에서는 location의 값이 원시 타입일 때와 객체 타입일 때의 렌더링 실행 유무를 알 수 있는 예제이다.
location 원시 타입일 땐 몇끼를 먹냐는 기능(편의상 '몇끼' 라고 하겠다.)을 작동 시켜도 useEffect는 작동하지 않는다.
하지만 반대로 객체 타입일 땐 작동을 한다.
그 이유는 원시 타입일 경우 변수에 지정된 값이 원시타입 그대로 저장 되기에 '몇끼'를 변경해도 location의 값은 '몇끼' 변경 이전과 이후의 값이 같기 때문에 useEffect가 활성화 되지 않는다.
하지만 location이 객체 타입이 된다면 그 값은 '주소'로 할당 받는다. 객체의 '주소'는 렌더링 될 때 마다 '새로운 주소'를 할당 받기 때문에 이전의 값과 현재의 값이 동일하지 않다고 인식한다. 그렇기 때문에 '몇끼'를 변경해도 렌더링이 되어 '새로운 주소'를 할당 받기 때문에 useEffect가 활성화가 된다.
useMemo를 통해 location 객체 타입을 memoize하게 되면 그 주소값 자체를 할당받을 수 있다.
무거운 데이터를 관리할 때 주로 이용해야 할 것 같다. 예를 들면 큰 배열을 관리 하는 게시판의 목록이나 다수의 데이터를 렌더링 할 때 사용될 듯 하다.