( ⚠️ 이 포스팅은 이전 포스팅에 이어진 내용 입니다. )
이전 포스팅에서 context 를 만들고 각각 context에 있는 값을 변경하기 위해 함수를 작성했었습니다.
예를 들어 A context 에 있는 state(값)를 바꾸기 위해 A'라는 함수를 작성하고, B context 에 값을 변경하기 위해 B' 함수를 만들었다고 가정합시다!
그러면 자연스럽게 만약 데이터가 아주아주 많고 다양하다면 ? 🤔
우리가 context를 나눴던 이유는 각각의 값들의 속성의 성격?종류? 가 다르기 때문에 나눴습니다. 그러나... 우리는 생각합니다..
😈 : context가 100개가 있고 만약 각각 다뤄야할 값이 100개라면 어쩔껀데???
🥲 : 저한테 왜그러세요..
만약 이전 포스팅과 같이 코딩을 했다면 각각의 context의 state 변경 함수를 알기위해 들어가서 필요한것을 찾고... 아무튼 복잡함! 🔥
이를 방지하고 간단히하기 위해 하나의 함수에서 상태와 원하는 액션을 하게 만들어주면 됩니다. 그렇게 나온 개념이 Reducer 입니다.
정의 하자면 Reducer = useState
를 사용하지 않고 상태를 관리하게 해줌 + 상태 업데이트 로직의 분리.
function reducer(state, action) {
// 새로운 상태를 만드는 로직
// 말은 어려워 보이지만 그냥 평범한 함수랑 다름이 없습니다!
return newState;
}
const [state, dispatch] = useReducer(reducer, initialState);
// dispatch : 액션을 발생시키는 트리거
//bookReducer.js
export const bookReducer = (state,action) =>{
switch(action.type) { // 이 부분에서 TS와 아주아주 찰떡!
case 'ADD_BOOK' : //새로운 북 추가
return [...state, {
title : action.book.title,
author: action.book.author,
id : uuid()
}]
case 'REMOVE_BOOK' : // 북 제거
return state.filter(book => book.id !== action.id)
default:
return state
}
}
👇 리듀서 적용
//BookContext.js
function BookContextProvider(props) {
const [books, dispatch] = useReducer(bookReducer,[]);
// (무슨리듀서?,초기dispatch)
// [사용할 state, 사용할 액션 불러올 commend같은 것]
/* const [books, setBooks] = useState([
{title: 'name of the wind', author:'patrick rothfuss',id: 1},
{title: 'the way of kings', author:'brandon sanderson', id: 2},
])
const addBook = (title,author) =>{
setBooks([...books,{title,author, id: uuid() }])
}
const removeBook = (id) =>{
setBooks(books.filter(book => book.id !== id))
}*/ 이전 코드
return(
<BookContext.Provider value ={{books, dispatch}}>
{props.children}
</BookContext.Provider>
)
}
👇 사용
//BookForm.js
function NewBookForm() {
const {dispatch} = useContext(BookContext);
const [title,setTitle] = useState('');
const [author,setAuthor] = useState('');
const handleSubmit = (e) =>{
e.preventDefault()
// addBook(title,author); 이렇게 함수 쓸게 아니라
dispatch({type : 'ADD_BOOK', book :{title,author}}); // dispatch로 알려줌
setTitle('');
setAuthor('');
}
return(
<form onSubmit={handleSubmit}>
<input type="text" placeholder="book title" value={title} onChange={(e) => setTitle(e.target.value)} required/>
<input type="text" placeholder="book author" value={author} onChange={(e) => setAuthor(e.target.value)} required/>
<input type="submit" value="add book" />
</form>
);
}
👇 다른 컴포넌트에도 적용
//BookDetail.js
function BookDetails ({book}) {
const {dispatch} = useContext(BookContext)
return(
<li onClick ={() => dispatch({type: 'REMOVE_BOOK', id: book.id})}>
{/* <li onClick ={() => removeBook(book.id)}> */}
<div className ="title"><h4> - {book.title}</h4></div>
<div className ="author">{book.author}</div>
</li>)
}
export default BookDetails