.png)

useMemo 는 메모이제이션된 값을 반환하게 합니다.
useEffect 와 유사하게 useMemo 는 의존성이 변경되었을 때에만 메모이제이션된 값만 다시 계산합니다.
한 가지 예시를 들어봅시다.
하위 컴포넌트가 상위 컴포넌트로부터 a 와 b 라는 두 개의 props 를 전달받습니다.
하위 컴포넌트는 이를 서로 다른 함수로 각각의 값을 가공한 새로운 값을 보여주는 역할을 합니다.
하위 컴포넌트는 props로 넘겨 받는 인자가 하나라도 변경될 때마다 렌더링되는데, 만약 props.a 만 변경 되었을 때 이전과 같은 값인 props.b도 다시 함수를 호출해서 재계산한다면 비효율적입니다.
useMemo 는 이러한 비효율성을 방지하기 위해, 변경되지 않은 것에 대해서는 메모이제이션된 값을 반환합니다.
하지만, 하위 컴포넌트내에서 각각의 값을 가공하는 함수를 처리하는 로직이 복잡하지 않다면 오히려 useMemo 를 사용하는 것이 더욱 비효율적일 수 있습니다.
다음 예시는 다음과 같은 구조를 가집니다.
📦public
┗ 📜index.html
📦src
┣ 📜App.js
┣ 📂components
┃ ┗ 📜Info.js
┃ ┣ 📜GetColor.js
┃ ┗ 📜GetDay.js
┗ 📜index.js
Info 컴포넌트는 GetColor 와 GetDay라는 하위 컴포넌트를 가집니다.
GetColor 는 영어로 색깔을 선택했을 때, 이를 한국어로 번역해서 반환해주는 컴포넌트입니다.
GetDay 는 영어로 요일을 선택했을 때, 이를 한국어로 번역해서 반환해주는 컴포넌트입니다.
먼저, useMemo 와 useCallback 을 사용하지 않고 사용해봅시다.
📌 와 🔍 이 체크된 부분은 코드가 곧 바뀔 곳입니다. 참고해주세요 :)
App.js
import React, { useState, useEffect, useMemo } from "react";
import Info from "./Info";
const App = () => {
const [color, setColor] = useState("");
const [season, setSeason] = useState("");
🔍 🔍 🔍
const onChangeHandler = (e) => {
if (e.target.id === "color") setColor(e.target.value);
else setSeason(e.target.value);
};
return (
<div className='App'>
<div>
<label>
What is your favorite color of rainbow ?
<input id='color' value={color} onChange={onChangeHandler} />
</label>
</div>
<div>
What is your Season ?
<label>
<input
type='radio'
name='season'
value='Spring'
onChange={onChangeHandler}
/>
Spring
</label>
<label>
<input
type='radio'
name='season'
value='Summer'
onChange={onChangeHandler}
/>
Summer
</label>
<label>
<input
type='radio'
name='season'
value='Fall'
onChange={onChangeHandler}
/>
Fall
</label>
<label>
<input
type='radio'
name='season'
value='Winter'
onChange={onChangeHandler}
/>
Winter
</label>
</div>
<Info color={color} season={season} />
</div>
);
};
export default App;
Info.js
import React from "react";
const getColorKor = (color) => {
console.log("getColorKor");
switch (color) {
case "red":
return "빨강";
case "orange":
return "주황";
case "yellow":
return "노랑";
case "green":
return "초록";
case "blue":
return "파랑";
case "navy":
return "남";
case "purple":
return "보라";
default:
return "레인보우";
}
};
const getSeason = (season) => {
console.log("getSeason");
switch (season) {
case "Spring":
return "봄";
case "Summer":
return "여름";
case "Fall":
return "가을";
case "Winter":
return "겨울";
default:
return "아직 잘 모름";
}
};
const Info = ({ color, season }) => {
📌 📌 📌
const colorKor = getColorKor(color);
const seasonKor = getSeason(season);
return (
<div className='info-wrapper'>
<br></br>
<span>
제가 가장 좋아하는 색은 <b>{colorKor}</b> 이고,{" "}
</span>
<br></br>
<span>
좋아하는 계절은 <b>{seasonKor}</b> 입니다.
</span>
</div>
);
};
export default Info;
다음과 같이 코드를 작성하고 실행해보면 아래와 같이
먼저 component 가 mount 가 되었을 때 동시에 1번 실행되고,
이후에 우리는 좋아하는 계절만 선택했음에도 불구하고,
getColor 이 getSeason 과 같이 실행됨을 알 수 있습니다.

이제 useMemo 를 사용해봅시다
아까 📌 이 체크된 부분을 바꿔봅시다.
const colorKor = useMemo(() => getColorKor(color), [color]);
const seasonKor = useMemo(() => getSeason(season), [season]);
위와 같이 코드를 바꾸고 실행해보면, Season이 선택되면 getSeason 만 호출되고, Color 가 선택되면
getColor 만 실행되는 것을 알 수 있습니다.


useMemo 는 메모이제이션된 함수를 반환하게 합니다.
컴포넌트가 렌더링 될 때마다 내부에 선언되어 있던 표현식(변수, 또다른 함수 등)도 매번 다시 선언되어 사용됩니다.
즉, App.js 의 onChangeHandler 함수는 내부의 color, season 상태값이 변경될 때마다 재선언된다는 것을 의미합니다. 하지만 onChangeHandler 함수는 파라미터로 전달받은 이벤트 객체(e)의 target.id 값에 따라 setState를 실행해주기만 하면 되기 때문에, 첫 마운트 될 때 한 번만 선언하고 재사용하면 되지 않을까요?
예제에서 🔍 이 체크된 부분을 바꿔봅시다.
const onChangeHandler = useCallback(e => {
if (e.target.id === "color") setColor(e.target.value);
else setMovie(e.target.value);
}, []);
useCallback 은 이벤트 핸들러 함수나 api를 요청하는 함수를 주로 useCallback 으로 선언하는 것을 알 수 있었습니다.
그리고 useCallback 또한 useMemo 와 동일하게 내부의 callback 함수의 로직이 복잡한 계산이 아니라면, 크게 의미있는 최적화는 아닐 수 있습니다. 공식문서에서도 다음과 같은 내용이 있습니다.

즉, optimized child 인 하위 컴포넌트에게 callback 함수를 props 를 넘길 때
상위 컴포넌트에서 useCallback 으로 함수를 선언하는 것이 유용하다는 의미로 해석할 수 있습니다.
하위 컴포넌트가 React.memo() 같은 것으로 최적화되어야만 useCallback 으로 함수를 선언하는 것이
최적화에 적용된다는 것을 알 수 있습니다. 다음 게시글에서는 React.memo 와 useCallback 을 함께 사용하는 방법에 대해서 알아보겠습니다.
React 공식문서
useCallback 과 React.memo 를 통한 렌더링 최적화
useMemo 와 useCallback 사용하기