웹 서비스의 성능을 개선하는 것
최적화
는 필수임컴포넌트 내부에서 다시 불필요한 연산을 수행하지 않도록 하는 hook
const getAnalyzedTodoData = () => {
const totalCount = todos.length;
const doneCount = todos.filter((todo) => todo.isDone).length;
const notDoneCount = totalCount - doneCount;
return {
totalCount,
doneCount,
notDoneCount,
};
};
const { totalCount, doneCount, notDoneCount } = getAnalyzedTodoData();
<div>
<div>전체 투두: {totalCount}</div>
<div>완료 투두: {doneCount}</div>
<div>미완 투두: {notDoneCount}</div>
</div>
const TodoList = ({ todos, onUpdate, onDelete }) => {
const [search, setSearch] = useState("");
const onChangeSearch = (e) => {
setSearch(e.target.value);
};
const filterTodos = () => {
if (search === "") {
return todos;
}
return todos.filter((todo) =>
todo.content.toLowerCase().includes(search.toLowerCase())
);
};
const getAnalyzedTodoData = () => {
console.log("Todo 분석 함수 호출");
const totalCount = todos.length;
const doneCount = todos.filter((todo) => todo.isDone).length;
const notDoneCount = totalCount - doneCount;
return {
totalCount,
doneCount,
notDoneCount,
};
};
const { totalCount, doneCount, notDoneCount } = getAnalyzedTodoData();
return (
<div className="TodoList">
<h4>오늘의 할 일</h4>
<div>
<div>전체 투두: {totalCount}</div>
<div>완료 투두: {doneCount}</div>
<div>미완 투두: {notDoneCount}</div>
</div>
<input
value={search}
onChange={onChangeSearch}
placeholder="검색어를 입력하세요"
/>
<div className="todos_wrapper">
{filterTodos().map((todo) => (
<TodoItem
key={todo.id}
{...todo}
onUpdate={onUpdate}
onDelete={onDelete}
/>
))}
</div>
</div>
);
};
onChangeSearch
가 실행 됨setSearch
가 호출되고search
의 상태가 업데이트 되기 때문const { 반환하는 값 } = useMemo(() => {
조건에 충족될 경우에만 실행되는 함수
}, [조건])
const { totalCount, doneCount, notDoneCount } = useMemo(() => {
console.log("Todo 분석 함수 호출");
const totalCount = todos.length;
const doneCount = todos.filter((todo) => todo.isDone).length;
const notDoneCount = totalCount - doneCount;
return {
totalCount,
doneCount,
notDoneCount,
};
}, [todos]);
function App() {
const [todos, dispatch] = useReducer(reducer, mockDate);
return (
<div className="App">
<Header />
<TodoEditor onCreate={onCreate} />
<TodoList todos={todos} onUpdate={onUpdate} onDelete={onDelete} />
</div>
);
}
import "./Header.css";
import { memo } from "react";
const Header = () => {
const options = {
weekday: "long",
year: "numeric",
month: "long",
day: "numeric",
};
const date = new Date().toLocaleDateString(undefined, options);
return (
<div className="Header">
<h1>{date}</h1>
</div>
);
};
export default memo(Header);
export default memo(Header)
최적화된 컴포넌트를 반환const TodoItem = ({ id, isDone, createdDate, content, onUpdate, onDelete }) => {
}
const mockDate = [
{
id: 0,
isDone: false,
content: "공부하기",
createdDate: new Date().getTime(),
},
]
cf. 참조자료형 중 함수는 변수를 저장할 때 그 값 그대로 저장하는 것이 아니라 참조값이 저장됨, 그러니까 새로 렌더링 될 때마다 함수에 저장된 참조값은 계속 변하는 형태
const onUpdate = useCallback((targetId) => {
dispatch({
type: "UPDATE",
data: targetId,
});
}, []);
const onDelete = useCallback((targetId) => {
dispatch({
type: "DELETE",
data: targetId,
});
}, []);
자식컴포넌트들에게 데이터를 직송으로 보내줄 수 있는 객체
import { createContext } from "react";
export const TodoContext = createContext();
<div className="App">
<Header />
<TodoContext.Provider value={(todos, onCreate, onUpdate, onDelete)}>
<TodoEditor onCreate={onCreate} />
<TodoList todos={todos} onUpdate={onUpdate} onDelete={onDelete} />
</TodoContext.Provider>
</div>
그리고 prop으로 내려받을 컴포넌트를 TodoContext.Provider
로 감싸줌
전달한 데이터를 value에 담아서 전달
즉, 자식컴포넌트들은 Provider가 제공하는 데이터를 다이렉트로 받아서 사용할 수 있음
import { useContext } from "react";
import { TodoContext } from "../TodoContext";
const TodoItem = ({ id, isDone, createdDate, content }) => {
const { onUpdate, onDelete } = useContext(TodoContext);
}
import { TodoContext } from "../TodoContext";
const TodoList = () => {
const { todos } = useContext(TodoContext);
}
Context를 했더니, 또 항목들이 렌더됨(최적화가 풀린듯)
import { createContext } from "react";
export const TodoStateContext = createContext();
export const TodoDispatchContext = createContext();
TodoStateContext
, TodoDispatchContext
를 만들어줌 <div className="App">
<Header />
<TodoStateContext.Provider value={todos}>
<TodoDispatchContext.Provider value={{ onCreate, onUpdate, onDelete }}>
<TodoEditor />
<TodoList />
</TodoDispatchContext.Provider>
</TodoStateContext.Provider>
</div>
const memoizedDispatches = useMemo(() => {
return {
onCreate,
onUpdate,
onDelete,
};
}, []);
<div className="App">
<Header />
<TodoStateContext.Provider value={todos}>
<TodoDispatchContext.Provider value={memoizedDispatches}>
<TodoEditor />
<TodoList />
</TodoDispatchContext.Provider>
</TodoStateContext.Provider>
</div>