useReducer hook
- useState를 대체할 수 있는 함수
- 복잡한 상태 관리가 필요한 경우 reducer를 사용할 수 있다.
- reducer는 이전 상태와 Action을 합쳐, 새로운 state를 만드는 조작을 말한다.
useReducer 함수
import React, { useReducer } from "react";
const [state, dispatch] = useReducer(reducer, initialState, init);
1. state
- 컴포넌트에서 사용할 상태
2. dispatch 함수
- 첫번째 인자인 reducer 함수를 실행시킨다.
- 컴포넌트 내에서 state의 업데이트를 일으키키 위해 사용하는 함수
3. reducer 함수
- 컴포넌트 외부에서 state를 업데이트 하는 함수
- 현재state, action 객체를 인자로 받아, 기존의 state를 대체하여 새로운 state를 반환하는 함수
4. initialState
- 초기 state
5. init
- 초기 함수 (초기 state를 조금 지연해서 생성하기 위해 사용)
예시)
dispatch 함수
- reducer 함수를 실행 시킨다.
- action 객체를 인자로 받으며 action 객체는 어떤 행동인지를 나타내는 type 속성과 해당 행동과 관련된 데이터(payload)를 담고 있다.
- action을 이용하여 컴포넌트 내에서 state의 업데이트를 일으킨다.
reducer 함수
- 상기 dispatch 함수에 의해 실행되며, 컴포넌트 외부에서 state를 업데이트 하는 로직을 담당 한다.
- 함수의 인자로는 state와 action을 받게 된다.
- state와 action을 활용하여 새로운 state를 반환 한다.
사용 방법 예시
export default function AppMentor() {
const [person, dispatch] = useReducer(personReducer, initialPerson);
const handleUpdate = () => {
const prev = prompt(`누구의 이름을 바꾸고 싶은가요?`);
const current = prompt(`이름을 무엇으로 바꾸고 싶은가요?`);
dispatch({ type: 'updated', prev, current });
};
const handleAdd = () => {
const name = prompt(`멘토의 이름은?`);
const title = prompt(`멘토의 직함은?`);
dispatch({ type: 'added', name, title });
};
const handleDelete = () => {
const name = prompt(`누구를 삭제하고 싶은가요?`);
dispatch({ type: 'deleted', name });
};
return (
<div>
<h1>
{person.name}는 {person.title}
</h1>
<p>{person.name}의 멘토는:</p>
<ul>
{person.mentors.map((mentor, index) => (
<li key={index}>
{mentor.name} ({mentor.title})
</li>
))}
</ul>
<button onClick={handleUpdate}>멘토의 이름을 바꾸기</button>
<button onClick={handleAdd}>멘토 추가하기</button>
<button onClick={handleDelete}>멘토 삭제하기</button>
</div>
);
}
const initialPerson = {
name: '쌀짱',
title: '개발자',
mentors: [
{
name: '킴',
title: '시니어개발자',
},
{
name: '제임스',
title: '시니어개발자',
},
],
};
personReducer
export default function personReducer(person, action) {
switch (action.type) {
case 'updated': {
const { prev, current } = action;
return {
...person,
mentors: person.mentors.map((mentor) => {
if (mentor.name === prev) {
return { ...mentor, name: current };
}
return mentor;
}),
};
}
case 'added': {
const { name, title } = action;
return {
...person,
mentors: [...person.mentors, { name, title }],
};
}
case 'deleted': {
return {
...person,
mentors: person.mentors.filter((mentor) => mentor.name !== action.name),
};
}
default: {
throw Error(`알수없는 액션 타입이다: ${action.type}`);
}
}
}