공식문서 참고하여 작성함
useState가 state를 setting함으로써 리액트에게 "무엇을 해라" 라고 말해주었다면, useReducer을 사용할 땐 이벤트 핸들러로부터 "유저가 방금 뭘 했는지" 그 액션을 전달(dispatch)할 뿐이다.
function handleAddTask(text) {
dispatch({
type: 'added',
id: nextId++,
text: text,
});
}
function handleChangeTask(task) {
dispatch({
type: 'changed',
task: task,
});
}
📌 dispatch function은 return value를 가지지 않는다.
Reducer function 은 current state와 action object를 파라미터로 갖고, next state를 반환한다. 그 반환된 next state로 state를 업데이트할 것임.
function tasksReducer(tasks, action) {
switch (action.type) {
case 'added': {
return [
...tasks,
{
id: action.id,
text: action.text,
done: false,
},
];
}
case 'changed': {
return tasks.map((t) => {
if (t.id === action.task.id) {
return action.task;
} else {
return t;
}
});
}
case 'deleted': {
return tasks.filter((t) => t.id !== action.id);
}
default: {
throw Error('Unknown action: ' + action.type);
}
}
}
Reducer function이 state인 tasks를 인자로 받기 때문에, tasks를 컴포넌트 외부에 선언해도 된다! 이것이 코드의 indentation level을 줄여줘서 보다 읽기 편한 코드가 됨.
📌 보통 reducer function 안에는 if/else문 대신에 switch 구문을 쓰는 것이 컨벤션이다.
const [tasks, dispatch] = useReducer(tasksReducer, initialTasks);
내가 만들어놓은 Reducer function(tasksReducer)을 useReducer hook에 사용한다.
useReducer은 hook이기 때문에 컴포넌트의 최상단에 위치해야 한다.
tasks의 initial value는 initialTasks가 된다.taksReducer에게 이벤트 타입을 전달하면, tasksReducer가 상태를 업데이트한다.📌 useReducer은 두 가지 값을 가진 array를 리턴한다.
import { useReducer } from 'react';
import AddTask from './AddTask.js';
import TaskList from './TaskList.js';
export default function TaskApp() {
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,
});
}
return (
<>
<h1>Prague itinerary</h1>
<AddTask onAddTask={handleAddTask} />
<TaskList
tasks={tasks}
onChangeTask={handleChangeTask}
onDeleteTask={handleDeleteTask}
/>
</>
);
}
//Reducer function
function tasksReducer(tasks, action) {
switch (action.type) {
case 'added': {
return [
...tasks,
{
id: action.id,
text: action.text,
done: false,
},
];
}
case 'changed': {
return tasks.map((t) => {
if (t.id === action.task.id) {
return action.task;
} else {
return t;
}
});
}
case 'deleted': {
return tasks.filter((t) => t.id !== action.id);
}
Reducer function은 아예 다른 파일에 만들어도 상관없다.