요르딩딩
섹션11. 최적화 본문
728x90
반응형
10.1) 최적화란
10.2) useMemo와 연산 최적화
import "./List.css";
import TodoItem from "./TodoItem";
import { useState, useMemo } from "react";
const List = ({ todos, onUpdate, onDelete }) => {
const [search, setSearch] = useState("");
const onChangeSearch = (e) => {
setSearch(e.target.value);
};
const getFilteredData = () => {
if (search === "") {
return todos;
}
return todos.filter((todo) =>
todo.content
.toLowerCase()
.includes(search.toLowerCase())
);
};
const filteredTodos = getFilteredData();
// 수치 기능 개발!!! 매번 반복문을 통해서 계산하는것은 비효율 적이기 때문에 메모기능 활용!!!
const { totalCount, doneCount, notDoneCount } =
useMemo(() => {
console.log("getAnalyzedData 호출!");
const totalCount = todos.length;
const doneCount = todos.filter(
(todo) => todo.isDone
).length;
const notDoneCount = totalCount - doneCount;
return {
totalCount,
doneCount,
notDoneCount,
};
}, [todos]); // todos가 변경될때만 앞의 콜백함수가 실행된다!!! useEffect와 동일!!! 빈값이면 최초한번만 수행됨!!
// 의존성배열 : deps
return (
<div className="List">
<h4>Todo List 🌱</h4>
<div>
<div>total: {totalCount}</div>
<div>done: {doneCount}</div>
<div>notDone: {notDoneCount}</div>
</div>
<input
value={search}
onChange={onChangeSearch}
placeholder="검색어를 입력하세요"
/>
<div className="todos_wrapper">
{filteredTodos.map((todo) => {
return (
<TodoItem
key={todo.id}
{...todo}
onUpdate={onUpdate}
onDelete={onDelete}
/>
);
})}
</div>
</div>
);
};
export default List;
10.3) React.memo와 컴포넌트 렌더링 최적화
# 컴포넌트의 불필요 리랜더링 제거
import "./Header.css";
import { memo } from "react"; // 추가!!!
const Header = () => {
return (
<div className="Header">
<h3>오늘은 📆</h3>
<h1>{new Date().toDateString()}</h1>
</div>
);
};
// 매번 랜더링될 필요없는 컴포넌트 최적화!!!
export default memo(Header); // 수정!!!
import "./TodoItem.css";
import { memo } from "react"; // 추가!!!
const TodoItem = ({
id,
isDone,
content,
date,
onUpdate,
onDelete,
}) => {
const onChangeCheckbox = () => {
onUpdate(id);
};
const onClickDeleteButton = () => {
onDelete(id);
};
return (
<div className="TodoItem">
<input
onChange={onChangeCheckbox}
readOnly
checked={isDone}
type="checkbox"
/>
<div className="content">{content}</div>
<div className="date">
{new Date(date).toLocaleDateString()}
</div>
<button onClick={onClickDeleteButton}>삭제</button>
</div>
);
};
// 수정!!! 얕은비교 (현재와 과거 객체) 매번 다르게 인식 -> HOC방식으로 적용
// export default memo(TodoItem);
//고차 컴포넌트 (HOC)
export default memo(TodoItem, (prevProps, nextProps) => {
//반환값에 따라, Props가 바뀌었는지 안바뀌었는지 판단
// T -> Props 바뀌지 않음 -> 리렌더링 X
// F -> Props 바뀜 -> 리렌더링 O
if(prevProps.id !== nextProps.id) return false;
if(prevProps.isDone !== nextProps.isDone) return false;
if(prevProps.content !== nextProps.content) return false;
if(prevProps.date !== nextProps.date) return false;
});
10.4) useCallback과 함수 재생성 방지
import "./App.css";
import { useRef, useReducer, useCallback } from "react";
import Header from "./components/Header";
import Editor from "./components/Editor";
import List from "./components/List";
const mockData = [
{
id: 0,
isDone: false,
content: "React 공부하기",
date: new Date().getTime(),
},
{
id: 1,
isDone: false,
content: "빨래하기",
date: new Date().getTime(),
},
{
id: 2,
isDone: false,
content: "노래 연습하기",
date: new Date().getTime(),
},
];
function reducer(state, action) {
switch (action.type) {
case "CREATE":
return [action.data, ...state];
case "UPDATE":
return state.map((item) =>
item.id === action.targetId
? { ...item, isDone: !item.isDone }
: item
);
case "DELETE":
return state.filter((item) => item.id !== action.targetId);
default:
return state;
}
}
function App() {
const [todos, dispatch] = useReducer(reducer, mockData);
const idRef = useRef(3);
const onCreate = useCallback((content) => {
dispatch({
type: "CREATE",
data: {
id: idRef.current++,
isDone: false,
content: content,
date: new Date().getTime(),
},
});
}, []); // 마운트 되었을때, 1번만 동작함!!!
const onUpdate = useCallback((targetId) => {
dispatch({
type: "UPDATE",
targetId: targetId,
});
}, []); // 마운트 되었을때, 1번만 동작함!!!
const onDelete = useCallback((targetId) => {
dispatch({
type: "DELETE",
targetId: targetId,
});
}, []); // 마운트 되었을때, 1번만 동작함!!!
return (
<div className="App">
<Header />
<Editor onCreate={onCreate} />
<List todos={todos} onUpdate={onUpdate} onDelete={onDelete} />
</div>
);
}
export default App;
import "./TodoItem.css";
import { memo } from "react"; // 추가!!!
const TodoItem = ({
id,
isDone,
content,
date,
onUpdate,
onDelete,
}) => {
const onChangeCheckbox = () => {
onUpdate(id);
};
const onClickDeleteButton = () => {
onDelete(id);
};
return (
<div className="TodoItem">
<input
onChange={onChangeCheckbox}
readOnly
checked={isDone}
type="checkbox"
/>
<div className="content">{content}</div>
<div className="date">
{new Date(date).toLocaleDateString()}
</div>
<button onClick={onClickDeleteButton}>삭제</button>
</div>
);
};
export default memo(TodoItem); //App에 useMemo적용으로 사용가능!!!
# 순서 : 1. 기능구현 -> 2.최적화
# 대상 : 연산, 함수, 컴포넌트 등
728x90
반응형
'[강의] > [한 입 크기로 잘라 먹는 리액트(React.js)]' 카테고리의 다른 글
섹션13. 프로젝트3. 감정 일기장 (0) | 2025.04.14 |
---|---|
섹션10. userReducer (0) | 2025.04.07 |
섹션9. 프로젝트2. TODO 리스트 (0) | 2025.04.02 |
섹션8. 라이프사이 (0) | 2025.04.02 |
섹션7. 프로젝트1. 카운터 (0) | 2025.04.02 |
Comments