useState 외의 다른 상태관리 hook
컴포넌트의 상태 업데이트 로직을 컴포넌트에서 분리시킬 수 있으며, 상태 업데이트 로직을 컴포넌트 바깥에 작성 할 수도 있고, 다른 파일에 불러와서 사용할 수 있다.
복잡한 상태를 다룰 때 유용하며, 유지보수시에도 유용
dispath에는 action의 type과 payload가 들어감
type은 어떤 액션인지 나타내줌, payload는 해당 행동과 관련된 데이터
dispath({type:"deposit", payload:number});
useReducer의 첫 번째 인자로는 reducer 함수를 받고, 두 번째 인자로는 상태의 초기 값을 받는다.
상태 값과 dispath 함수를 반환함
const [money, dispatch] = useReducer(reducer, 0);
const ACTION_TYPES = {
deposit: "deposit",
withdraw: "withdraw",
};
import { useReducer, useState } from "react";
// reducer : state 업데이트
// dispatch : 요구 사항
// action : 요구 내용
const ACTION_TYPES = {
deposit: "deposit",
withdraw: "withdraw",
};
const reducer = (state, action) => {
// 전달받은 action대로 state 변경
switch (action.type) {
case ACTION_TYPES.deposit:
return state + action.payload;
case ACTION_TYPES.withdraw:
return state - action.payload;
default:
return state;
}
};
function App() {
const [number, setNumber] = useState(0);
// 새로 만든 요소, dispatch함수
// reducer 함수, 상태 초기값
// dispatch 실행시 reducer가 호출됨
const [money, dispatch] = useReducer(reducer, 0);
return (
<div>
<h2>useReducer 은행</h2>
<p>잔고: {money}원</p>
<input
type="number"
value={number}
onChange={(e) => setNumber(parseInt(e.target.value))}
/>
<button onClick={() => dispatch({ type: "deposit", payload: number })}>
예금
</button>
<button onClick={() => dispatch({ type: "withdraw", payload: number })}>
송금
</button>
</div>
);
}
export default App;
상태 변경을 두 가지 action를 통해 관리
import { useReducer, useState } from "react";
import Student from "./Student";
// reducer : state 업데이트
// dispatch : 요구 사항
// action : 요구 내용
const ACTION_TYPES = {
addStudent: "add-student",
deleteStudent: "delete-student",
checkStudent: "check-student",
};
const reducer = (state, action) => {
switch (action.type) {
case ACTION_TYPES.addStudent:
const name = action.payload.name;
const newStudent = {
id: Date.now(),
name,
isHere: false,
};
return {
count: state.count + 1,
students: [...state.students, newStudent],
};
case ACTION_TYPES.deleteStudent:
return {
count: state.count - 1,
students: state.students.filter(
(student) => student.id !== action.payload.id
),
};
case ACTION_TYPES.checkStudent:
return {
count: state.count,
students: state.students.map((student) => {
if (student.id === action.payload.id) {
return { ...student, isHere: !student.isHere };
}
return student;
}),
};
default:
return state;
}
};
const initalState = {
count: 0,
students: [],
};
function App() {
const [name, setName] = useState("");
const [studentInfo, dispatch] = useReducer(reducer, initalState);
return (
<div>
<h2>출석부</h2>
<p>총 학생 수: {studentInfo.count}명</p>
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
/>
<button
onClick={() =>
dispatch({ type: ACTION_TYPES.addStudent, payload: { name } })
}
>
추가
</button>
{studentInfo.students.map((student) => {
return (
<Student
key={student.id}
name={student.name}
dispatch={dispatch}
id={student.id}
isHere={student.isHere}
ACTION_TYPES={ACTION_TYPES}
/>
);
})}
</div>
);
}
export default App;
import React from "react";
export default function Student({ name, dispatch, id, isHere, ACTION_TYPES }) {
return (
<div>
<span style={{
textDecoration: isHere ? "line-through" : "none",
color: isHere ? "gray" : "black"
}}
onClick={() => dispatch({ type: ACTION_TYPES.checkStudent, payload: { id } })}
>
{name}
</span>
<button
onClick={() => dispatch({ type: ACTION_TYPES.deleteStudent, payload: { id } })}
>
삭제
</button>
</div>
);
}
상태 초기값을 userInfo 객체로 만듬
상태를 세 가지의 action를 통해 관리