일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- TS
- 인터섹션
- async/await
- map
- Promise
- 리터럴 타입
- 타입 좁히기
- 호이스팅
- 이분 검색
- app router
- RTK Query
- 반공변성
- ESlint
- CORS
- React
- Jest
- webpack
- 무한 스크롤
- recoil
- SSR
- 결정 알고리즘
- useAppDispatch
- 투포인터
- autosize
- dfs
- Cypress
- CI/CD
- tailwind
- 공변성
- 태그된 유니온
- Today
- Total
짧은코딩
최적화 1 - useMemo 본문
Memoization
이미 계산 해 본 연산 결과를 기억 해 두었다가 동일한 계산을 시키면, 다시 연산하지 않고 기억했던 데이터를 반환 시키게 하는 방법
-Memoization이 리엑트의 어떤 부분에 적용되어야 하는지
App.js
import { useEffect, useRef, useState } from "react";
import "./App.css";
import DiaryEditor from "./DiaryEditor";
import DiaryList from "./DiaryList";
const 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 {
author: it.email,
content: it.body,
emotion: Math.floor(Math.random() * 5) + 1,
created_date: new Date().getTime(),
id: dataId.current++,
};
});
setData(initData);
};
useEffect(() => {
getData();
}, []);
const onCreate = (author, content, emotion) => {
const created_date = new Date().getTime();
const newItem = {
author,
content,
emotion,
created_date,
id: dataId.current,
};
dataId.current += 1;
setData([newItem, ...data]);
};
const onRemove = (targetId) => {
const newDiaryList = data.filter((it) => it.id !== targetId);
setData(newDiaryList);
};
const onEdit = (targetId, newContent) => {
setData(
data.map((it) =>
it.id === targetId ? { ...it, content: newContent } : it
)
);
};
const getDiaryAnalysis = () => {
console.log("일기 분석 시작");
const goodCount = data.filter((it) => it.emotion >= 3).length;
const badCount = data.length - goodCount;
const goodRatio = (goodCount / data.length) * 100;
return { goodCount, badCount, goodRatio };
};
const { goodCount, badCount, goodRatio } = getDiaryAnalysis();
return (
<div className="App">
<DiaryEditor onCreate={onCreate} />
<div>전체 일기 : {data.length}</div>
<div>기분 좋은 일기 개수 : {goodCount}</div>
<div>기분 나쁜 일기 개수 : {badCount}</div>
<div>기분 좋은 일기 비율 : {goodRatio}</div>
<DiaryList onEdit={onEdit} onRemove={onRemove} diaryList={data} />
</div>
);
};
export default App;
이렇게 3이상이 기분이 좋은거라고 치고 비율을 출력해주는 기능을 만들었다.
이렇게 하면 "일기 분석 시작"이 콘솔에 2번 나오게된다.
App 컴포넌트가 처음 마운트가 될 때, useState의 값은 빈 배열이라 getDiaryAnalysis를 한번 호출한다.
그리고 getData에서 API 호출하고 setData가 이루어지면서 데이터가 한번 바뀌게된다. 그러면 App이 리렌더가 일어난다. 그러면서 모든 함수들이 재생성이 되고 const { goodCount, badCount, goodRatio } = getDiaryAnalysis();가 다시 수행되면서 getDiaryAnalysis()가 다시 호출된다.
리렌더링이 일어난다는건 App()가 한번 더 호출된다는 뜻이다. 따라서 getDiaryAnalysis가 2번 동작한다.
여기서 댓글을 수정하면 또 리렌더가 일어나서 getDiaryAnalysis가 한번 더 동작한다.
근데 이것은 좀 낭비다. 왜냐하면 댓글 수정은 기분 감정 점수에 영향을 못미쳐서이다.
const getDiaryAnalysis = useMemo(() => {
console.log("일기 분석 시작");
const goodCount = data.filter((it) => it.emotion >= 3).length;
const badCount = data.length - goodCount;
const goodRatio = (goodCount / data.length) * 100;
return { goodCount, badCount, goodRatio };
}, [data.length]);
const { goodCount, badCount, goodRatio } = getDiaryAnalysis;
연산을 최적화 하기 위해서는 useMemo를 사용하면 된다.
useMemo는 최적화 하고 싶은, Memoization하고 싶은 함수를 감싸주면 된다.
그러면 getdiaryAnalysis는 useMemo를 호출한 결과값처럼 되었고 useMemo 함수 안에 콜백 함수로 원래 getDiaryAnalysis 함수가 수행하는 기능을 전달한 꼴이 되었다.
useMemo는 첫번째 인자로 콜백 함수를 받아서 콜백 함수가 리턴하는 값, 즉 연산을 최적화 할 수 있도록 도와준다.
두번째 인자로는 배열을 전달하는데 useEffect의 두번째 인자와 똑같은 배열이다. 위 처럼 배열에 [data.length]를 넣어두면 data.length가 변했을 때만, 첫번째 인자인 콜백 함수가 다시 수행된다. 따라서 밑에서 아무리 getDiaryAnalysis를 호출해도 data.length가 변하지 않으면 그냥 똑같은 리턴을 계산하지 않고 반환하게된다.
그리고 getDiaryAnalysis는 이제 더 이상 함수가 아니게된다. 왜냐면 값을 리턴 받기 때문이다. 따라서 밑에 호출도 getDiaryAnalysis()가 아닌 getDiaryAnalysis로 사용해야 에러가 발생하지 않는다.
그리고 일기를 수정해보면 "일기 분석 시작"이 콘솔에 찍히지 않는다.
하지만 일기를 삭제하면 데이터 수가 바껴서 "일기 분석 시작"이 콘솔에 찍힌다.
'인프런, 유데미 > 한입 크기로 잘라 먹는 리액트' 카테고리의 다른 글
최적화3-컴포넌트 최적화 (0) | 2022.05.29 |
---|---|
최적화2-컴포넌트 재사용 (0) | 2022.05.28 |
React developer tools (0) | 2022.05.27 |
React에서 API 호출하기 (0) | 2022.05.26 |
Lifecycle 제어하기 (0) | 2022.05.26 |