리액트에서 상태를 업데이트할 때 새로운 배열 또는 객체로 반환해야 한다.
useReducer를 사용하면 복잡한 객체를 추가/삭제/수정하는 코드를 다른 파일에 보관해 코드를 재사용할 수 있다!
기존에 useState로 상태값을 업데이트할 때 새로운 배열을
만들어 반환하는 모습이다.
import { useState } from 'react';
import AddTask from './AddTask.js';
import TaskList from './TaskList.js';
export default function TaskApp() {
const [tasks, setTasks] = useState(initialTasks);
function handleAddTask(text) {
setTasks([
...tasks,
{
id: nextId++,
text: text,
done: false,
},
]);
}
function handleChangeTask(task) {
setTasks(
tasks.map((t) => {
if (t.id === task.id) return task;
return t;
})
);
}
function handleDeleteTask(taskId) {
setTasks(tasks.filter((t) => t.id !== taskId));
}
return (
<>
<h1>Prague itinerary</h1>
<AddTask onAddTask={handleAddTask} />
<TaskList
tasks={tasks}
onChangeTask={handleChangeTask}
onDeleteTask={handleDeleteTask}
/>
</>
);
}
let nextId = 3;
const initialTasks = [
{id: 0, text: 'Visit Kafka Museum', done: true},
{id: 1, text: 'Watch a puppet show', done: false},
{id: 2, text: 'Lennon Wall pic', done: false},
];
➡️ 상태를 업데이트하는 로직을 컴포넌트 밖으로 빼오면 유지 및 관리하기가 좋으며 다른 컴포넌트에서도 재사용할 수 있다!
💡 <useState에서 useReducer로 변경하는 방법>
function handleAddTask(text) {
setTasks([
...tasks,
{
id: nextId++,
text: text,
done: false,
},
]);
}
function handleChangeTask(task) {
setTasks(
tasks.map((t) => {
if (t.id === task.id) {
return task;
} else {
return t;
}
})
);
}
function handleDeleteTask(taskId) {
setTasks(tasks.filter((t) => t.id !== taskId));
}
``
setTasks
처럼 작업 상태를 설정하지 않고export default function tasksReducer(tasks, action) {
switch(action.type){
case 'added': {
const {id,text} = action;
return [
...tasks,
{
id,
text,
done: false,
},
];
}
case 'changed': {
const {task} = action;
return tasks.map((t) => {
if (t.id === action.task.id) return task;
return t;
});
}
case 'deleted': {
const {id} = action;
return tasks.filter((t) => t.id !== id);
}
default: {
throw Error(`Unknown action:${action.type}`);
}
}
tasks
데이터를 받아오고 무슨 행동을 원하는지에 대한 정보 action을 받아온다. 이때 액션 타입은 dispatch를 통해 우리가 따로 지정한다. tasks
데이터를 추가/수정/삭제에 따라setTasks
에 정의한 코드 이용)useReducer를 사용할 때 초기 상태값(intialTasks
)과 새로운 상태를 만들어 나갈 함수(tasksReducer
)를 전달한다.
import { useReducer } from 'react';
const [tasks, dispatch] = useReducer(tasksReducer, initialTasks);
function handleAddTask(text) {
dispatch({type:'added',id: nextId++,text: text});
}
function handleChangeTask(task) {
dispatch({type: 'changed',task: task});
}
function handleDeleteTask(taskId) {
dispatch({ type: 'deleted',id: taskId});
}
tasks
와 tasksReducer
함수를 호출할 수 있는 dispatch를 통해 우리가 원하는 액션을 명령할 수 있다. 예를 들어, dispatch({type:'added',id: nextId++,text: text}); 호출하면 useReducer가 자동으로 tasksReducer
함수를 호출한다. 이때 추가 시 필요한 데이터 id와 text 데이터도 같이 전달한다.
상태 관리하는 곳에서 action 객체를 통해 필요한 데이터를 받아와 기존의 tasks
데이터에서 새로운 데이터를 추가할 수 있게 된다.