연산 결과 재사용 하는 방법
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(); // 함수로 호출한 결과 값을 객체로 반환
getDiaryAnalysis
함수를 선언하여 filter 를 이용하여 emotion
>= 3 이상인 것을 goodCount
에 담았습니다.badCount
는 전체 일기에서 goodCount
를 뺀 수 goodRatio
는 전체에서 (goodCount / data.length) * 100;
한 값 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>
);
console.log('일기 분석 시작')
이 2번 찍혀서 나옵니다.import { useEffect, useRef, useState } from 'react';
import './App.css';
import DiaryEditor from './DiaryEditor';
import DiaryList from './DiaryList';
function App() {
// API 호출 함수
const getData = async () => {
const res = await fetch(
'https://jsonplaceholder.typicode.com/comments'
).then((res) => res.json());
// 가져와서 사용할 데이터 ( 0 ~ 20 )
const initData = res.slice(0, 20).map((it) => {
return {
author: it.email,
content: it.body,
emotion: Math.floor(Math.random() * 5) + 1,
create_date: new Date().getTime(),
id: dataId.current++,
};
});
setData(initData);
};
useEffect(() => {
getData();
}, []);
const [data, setData] = useState([]); // state-배열로 저장할 예정 (리스트)
const dataId = useRef(0);
const onCreate = (author, content, emotion) => {
const create_date = new Date().getTime();
const newItem = {
author,
content,
emotion,
create_date,
id: dataId.current, // 0 을 가리킨다.
};
dataId.current += 1; // id 의 값이 1씩 증가한다.
setData([newItem, ...data]); // 새로운 아이템이 위로 올라오게 하기 위해서 newItem 을 먼저 사용
};
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 = 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 };
};
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;
App
컴포넌트가 첫 Mount 가 될 때, data
state 의 값은 빈 배열이었습니다.const [data, setData] = useState([]);
const {goodCount, badCount, goodRatio} = getDiaryAnalysis();
함수를 한 번 호출하게 됩니다.setData(initData)
가 이루어지게 되면서const getData = async () => {
const res = await fetch(
'https://jsonplaceholder.typicode.com/comments'
).then((res) => res.json());
// 가져와서 사용할 데이터 ( 0 ~ 20 )
const initData = res.slice(0, 20).map((it) => {
return {
author: it.email,
content: it.body,
emotion: Math.floor(Math.random() * 5) + 1,
create_date: new Date().getTime(),
id: dataId.current++,
};
});
setData(initData);
};
data
가 한 번 바뀌게 됩니다.App
컴포넌트가 리렌더가 일어나기 때문에 App
컴포넌트 안의 모든 함수들이 재생성이 되게 되고, 2번의 코드가 다시 수행이 되어 호출 됩니다.만약, 일기를 수정하게 되면 data
state 의 상태가 변했기 때문에 App
컴포넌트가 한 번 더 리렌더가 일어납니다. 그렇게 되면 getDiaryAnalysis
는 또 실행이 됩니다.
하지만 데이터를 수정하는 것은 일기 분석의 결과, 즉 emotion 에 아무런 영향을 미칠 수 없는데 계속 호출이 됩니다.
이런 경우 useMemo
를 사용 할 수 있습니다.
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] // 두 번째 인자
);
import
를 하고, 최적화 하고 싶은 함수를 감싸주면 됩니다.[data.lenght]
가 변화 할 때 만 콜백함수가 다시 수행하게 됩니다. data
의 state 가 변해도, [data.lenght]
가 변하지 않는 이상 getDiaryAnalysis
는 호출 하지 않습니다.하지만 위의 코드를 그대로 실행하면 오류가 납니다. useMemo로 감싸고 , 의존성 배열을 전달을 해서 함수를 최적화를 하면, 더 이상 함수가 아니게 됩니다!
useMemo 기능은 함수를 전달을 받아서 콜백함수가 리턴하는 값을 리턴하게 됩니다.
const getDiaryAnalysis
는 함수가 아니라 값을 리턴 받게 됩니다.//const { goodCount, badCount, goodRatio } = getDiaryAnalysis(); X
const { goodCount, badCount, goodRatio } = getDiaryAnalysis;
useMemo
를 사용해서 의존성 배열에 어떤 값이 변화할 때만 연산을 다시 실행 할 것인지 명시하게 되면 const memoizedValue = useMemo(값 생성 함수, 의존성 배열);