어떤 컴포넌트가 최적화 대상인지
찾아낼 수 있어야 한다React Developers Tools
기능 활용 (Setting > General)Highlight updates when components render
: 어떤 컴포넌트가 지금의 행동에 의해서 리렌더링이 일어나고 있는지 색깔로 표시해주는 기능
예 : 일기 하나를 삭제하면 나머지 일기 컴포넌트들도 깜빡이면서 리렌더링이 일어나고 있다고 알려주고 있음
useEffect와 console을 확인하면 다 확인할 수 있지만, 지금 실습처럼 컴포넌트를 적게 만든 게 아니라 실제 Product를 개발했을 때 10~20개 이상의 컴포넌트 생성/유지하는 상황이라면 특정 컴포넌트만 찾아 useEffect와 console을 일일이 작성하는 일은 굉장히 번거롭게 됨
따라서, Highlight updates when components render
기능을 활용해 지금 어떤 컴포넌트가 연산 낭비되고 있는지 확인해보자.
작성 폼인 상단의 DiaryEditor 컴포넌트를 최적화시켜보기
✔️ 컴포넌트는 언제 렌더링하는지 생각해보기
- 본인이 가진 state에 변화가 생겼을 경우
- 부모 컴포넌트가 리렌더링이 일어날 경우
- 자신이 받은 prop이 변경될 경우
src/DiaryEditor.js
import { useState, useRef } from "react";
const DiaryEditor = ({onCreate}) => {
const [state, setState] = useState({
author: "", content: "", emotion: 1,
});
...
}
src/DiaryEditor.js
// 최상단
import React, { useEffect, useState, useRef } from "react";
// 최하단
export default React.memo(DiaryEditor);
React.memo
로 묶어주기React.memo로 묶인 DiaryEditor를 밖으로 내보내겠다는 의미
useEffect(()=>{
console.log("DiaryEditor Render");
});
src/App.js
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());
console.log(res);
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();
},[]);
2번의 렌더링이 된 것
그렇기 때문에 DiaryEditor가 전달받는 onCreate 함수도 App 컴포넌트가 렌더링이 되면서 계속 다시 생성되는 것
그런데 onCreate 함수는 다시 생성이 되어도 똑같음
이전 시간에 배운 비원시타입의 자료형의 비교
는 React.memo에서 얉은 비교
로 일어나기 때문에 결론적으로 prop으로 받고 있는 onCreate 함수가 App 컴포넌트가 렌더링될 때마다 계속 다시 만들어져서 onCreate를 prop으로 전달하는 것때문에 리렌더링이 발생하고 있는 문제
일기를 삭제하면 DiaryEditor가 다시 렌더됨 (onCreate는 App 컴포넌트가 렌더링될 때마다 재생성되므로)
📌 결론 : onCreate 함수가 재생성되지 않아야만 React.memo와 함께 최적화할 수 있음
src/App.js
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]);
};
src/App.js
import { useMemo, useEffect, useRef, useState, useCallback } from "react";
function App() {
const onCreate = useCallback(
(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]);
}, []);
}
[]
(Dependency Array)에 아무것도 안 넣어줘서 그럼그 당시의 data state의 값이 빈 배열
이므로 이런 현상이 발생✔️ 함수는 컴포넌트가 재생성될 때 다시 생성되는 이유가 있다
왜냐하면현재의 state 값을 참조
할 수 있어야 하기 때문이다
이 onCreate 함수가 알고 있는 data의 값은 그대로 빈 배열임
setData([newItem, ...data]);
함수형 업데이트
인자를 data를 받아서 newItem을 추가한 data를 리턴하는 콜백함수를 setData에 전달
const onCreate = useCallback(
(author, content, emotion) => {
const created_date = new Date().getTime();
const newItem = {
author,
content,
emotion,
created_date,
id: dataId.current
};
dataId.current += 1;
setData((data)=>[newItem, ...data]);
}, []);