이미 계산해 본 결과를 기억 해 두었다가 동일한 계산을 시키면, 다시 연산하지 않고 기억해두었던 데이터를 반환 시키게 하는 방법입니다.
먼저 예제 코드를 만들어 보도록 하겠습니다.
import { useEffect, useRef, useState } from "react";
import "./App.css";
import DiaryEditor from "./DiaryEditor";
import DiaryList from "./DiaryList";
import Lifecycle from "./Lifecycle";
function App() {
const [data, setData] = useState([]);
const dataId = useRef(0);
const getData = async () => {
const res = await fetch(
"https://jsonplaceholder.typicode.com/comments"
).then((res) => res.json());
const initData = res.slice(0, 20).map((it) => {
return {
name: it.email,
content: it.body,
hungry: (Math.floor(Math.random() * 9) + 1) * 10,
created_date: new Date().getTime(),
id: dataId.current++,
};
});
setData(initData);
};
useEffect(() => {
getData();
}, []);
const onCreate = (name, content, hungry) => {
const created_date = new Date().getTime();
const newItem = {
name,
content,
hungry,
created_date,
id: dataId.current,
};
dataId.current += 1;
setData([newItem, ...data]);
};
const onRemove = (targetId) => {
const newDirayList = data.filter((it) => it.id !== targetId);
setData(newDirayList);
};
const onEdit = (targetId, newContent) => {
setData(
data.map((it) =>
it.id === targetId ? { ...it, content: newContent } : it
)
);
};
const getDiaryAnalysis = () => {
console.log("일기 분석 시작");
const reallyHungy = data.filter((it) => it.hungry >= 80).length;
const notHungry = data.filter((it) => it.hungry < 40).length;
const reallyHungryRatio = (reallyHungy / data.length) * 100;
const notHungryRatio = (notHungry / data.length) * 100;
return { reallyHungy, notHungry, reallyHungryRatio, notHungryRatio };
};
const { reallyHungy, notHungry, reallyHungryRatio, notHungryRatio } =
getDiaryAnalysis();
return (
<div className="App">
<Lifecycle />
<DiaryEditor onCreate={onCreate} />
<div>전체 일기 : {data.length}</div>
<div>배부른 일기 개수 : {notHungry}</div>
<div>배고픈 일기 개수 : {reallyHungy}</div>
<div>배부른 일기 비율 : {notHungryRatio}</div>
<div>배고픈 일기 비율 : {reallyHungryRatio}</div>
<DiaryList onEdit={onEdit} onRemove={onRemove} diaryList={data} />
</div>
);
}
export default App;
기존 코드에 일기분석을 하는 코드를 추가하였습니다.
const getDiaryAnalysis = () => {
console.log("일기 분석 시작");
const reallyHungy = data.filter((it) => it.hungry >= 80).length;
const notHungry = data.filter((it) => it.hungry < 40).length;
const reallyHungryRatio = (reallyHungy / data.length) * 100;
const notHungryRatio = (notHungry / data.length) * 100;
return { reallyHungy, notHungry, reallyHungryRatio, notHungryRatio };
};
const { reallyHungy, notHungry, reallyHungryRatio, notHungryRatio } =
getDiaryAnalysis();
return (
<div className="App">
<Lifecycle />
<DiaryEditor onCreate={onCreate} />
<div>전체 일기 : {data.length}</div>
<div>배부른 일기 개수 : {notHungry}</div>
<div>배고픈 일기 개수 : {reallyHungy}</div>
<div>배부른 일기 비율 : {notHungryRatio}%</div>
<div>배고픈 일기 비율 : {reallyHungryRatio}%</div>
<DiaryList onEdit={onEdit} onRemove={onRemove} diaryList={data} />
</div>
);
해당 코드에는 새롭게 추가되는 개념이 없어서 설명은 넘어가도록 하겠습니다.
원하는대로 잘 출력되는 것을 확인할 수 있습니다.
콘솔로 로그를 보도록 하겠습니다.
일기 분석 시작이 2번 실행 된 것을 확인할 수 있습니다. 연한 색의 로그는 무시하셔도 됩니다.
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
index.js에 App 태그를 React.StrictMode로 감싸고 있기 때문에 연한색 글씨의 로그가 생기게 되는 것입니다.
무튼 2번 로그가 출력된다는 것은 2번 렌더링이 된다는 말입니다.
Mount 될 때 한번 출력되고,
const { reallyHungy, notHungry, reallyHungryRatio, notHungryRatio } = getDiaryAnalysis();
위의 코드가 실행되면서 두번 렌더링이 되는 것 입니다. 리렌더링 된다는 것은 App함수가 또 호출된다는 말입니다.
일기를 수정해 보았습니다. 그러자 또 getDiaryAnalysis 함수가 실행이 됩니다. 이것은 낭비입니다. 이유는 일기 내용을 수정한다고 해서 통계에 영향을 미치지는 않기 때문입니다. 이 때 사용하는 것이 "Memoization" 기법입니다.
App.js
import { useEffect, useMemo, useRef, useState } from "react";
const getDiaryAnalysis = useMemo(() => {
console.log("일기 분석 시작");
const reallyHungy = data.filter((it) => it.hungry >= 80).length;
const notHungry = data.filter((it) => it.hungry < 40).length;
const reallyHungryRatio = (reallyHungy / data.length) * 100;
const notHungryRatio = (notHungry / data.length) * 100;
return { reallyHungy, notHungry, reallyHungryRatio, notHungryRatio };
}, [data.length]);
사용법은 간단합니다. 함수를 useMemo로 감싸고 두번째로 배열을 넘겨야 하는데 useEffect와 마찬가지로 dependency array입니다. 즉, data의 length가 변경되어야 콜백함수가 실행되게 되는 것 입니다.
이렇게 변경을 하고 저장을 누르면 에러가 발생하게 됩니다.
getDiaryAnalysis는 함수가 아니라는 에러입니다. useMemo로 감싸게 되면 더이상 함수가 아니게 됩니다. useMemo는 안에 callback함수가 리턴하는 값을 리턴합니다.
const { reallyHungy, notHungry, reallyHungryRatio, notHungryRatio } =
getDiaryAnalysis();
위의 코드를 변경시키면 됩니다.
const { reallyHungy, notHungry, reallyHungryRatio, notHungryRatio } =
getDiaryAnalysis;
이제 일기의 내용을 변경해도 getDiaryAnalysis가 수행되지 않는 것을 확인할 수 있습니다.
해당 게시글은 인프런 강의
"한입 크기로 잘라 먹는 리액트(React.js) : 기초부터 실전까지(이정환)"
를 정리한 내용입니다. 쉽게 잘 설명해주시니 여러분도 강의를 듣는 것을 추천드립니다.