App.js
import { Provider } from 'react-redux'; import store from './store'; ... function App() { return ( <Provider store={store}> // Provider 설정 & store 연결 <div id="app"> <Header /> <main id="main"> <Routes> <Route path="/" element={<Question />} /> <Route path="/questions/:questionId" element={<DetailPage />} /> <Route path="/posts/:questionId/edit/:answerId" element={<EditAnswerPage />} /> <Route path="/bookmark" element={<BookmarkPage />} /> ... </Route> </Routes> </main> </div> </Provider> ); } export default App;
(1) slice 이름 정하기 🌈
(2) 초기값 설정하기
(3) 리듀서 만들기
(리듀서: action의 type에 따라 상태를 변경시키는 함수)
bookmarkSlice.js
import { createSlice } from '@reduxjs/toolkit'; // 1) createSlice 불러오기 const bookmarkSlice = createSlice({ // 2) Slice 만들기 name: 'myBookmarks', // slice의 이름 정하기 initialState: { // 초기값 설정 question_bookmarks: [ { questionId: 300, title: '😀 Question Bookmark Sample', content: '🍉 Small question on Spring Boot, and how to use a design pattern combined with Spring @Value configuration in order to select the appropriate @Repository please.n', question_tag: ['mysql', 'database'], totalRecommend: 2, createdAt: 'Dec 19 at 5:48', member_id: 'Mimi', }, ], answer_bookmarks: [ { answerId: 100, content: 'Answer Bookmarks 샘플입니다', recommend: 2, createdAt: 'Dec 13 at 12:06', choose: false, member_id: 'Lily', questionId: 1, }, ], }, reducers: { // 리듀서 만들기 add_question_bookmark: (state, action) => { state.question_bookmarks = [...state.question_bookmarks, action.payload]; }, remove_question_bookmark: (state, action) => { state.question_bookmarks = state.question_bookmarks.filter( (item) => item.questionId !== action.payload.questionId ); }, add_answer_bookmark: (state, action) => { state.answer_bookmarks = [...state.answer_bookmarks, action.payload]; }, remove_answer_bookmark: (state, action) => { state.answer_bookmarks = state.answer_bookmarks.filter( (item) => item.answerId !== action.payload.answerId ); }, }, }); export default bookmarkSlice; export const { //3) 액션 자동 생성 문법을 구조분해할당으로 내보내기 add_question_bookmark, remove_question_bookmark, add_answer_bookmark, remove_answer_bookmark, } = bookmarkSlice.actions;
Slice들을 모아서 하나의 Store 만들기
reducer
의 값은 객체이고, 이 객체의 키-값 쌍은 각각 하나의 slice에 대한 리듀서bookmarkReducer
)는 이후 useSelector를 이용해 state 받아올 때 사용Store.js
import { configureStore } from '@reduxjs/toolkit'; // 1) configureStore 불러오기 import bookmarkSlice from './detail/bookmarkSlice'; // 2) 만들어놓은 Slice들 불러오기 const store = configureStore({ // 3) store 만들기 reducer: { bookmarkReducer: bookmarkSlice.reducer, // 해당 slice의 reducer 이름 정해주기 🌈 (이후 useSelector 이용해 상태 받아올 때 사용) }, }); export default store;
action 타입
= case명
의 형태) 중 필요한 것 불러오기remove_question_bookmark(question)
, remove_answer_bookmark(answer)
는 액션 자동으로 생성하는 문법.remove_question_bookmark
, remove_answer_bookmark
가 함수가 아님.액션 자동으로 생성하는 문법
slice명.actions.case명(payload로 보낼 데이터)
- 원래는
bookmarkSlice.actions.remove_question_bookmark(payload로 보낼 데이터)
형태이지만 위에서 구조분해할당 했으므로remove_question_bookmark(payload로 보낼 데이터)
형태가 된다.
BookmarkPage.js
- 북마크 삭제하기
import { useDispatch } from 'react-redux'; import { // 1) 북마크 삭제에 필요한 리듀서들 불러오기 remove_answer_bookmark, remove_question_bookmark, } from '../detail/bookmarkSlice'; export const BookmarkItem = ({ question, answer }) => { // 질문, 답변 데이터 인자로 전달 const dispatch = useDispatch(); // useDispatch() 사용 return ( <DetailBody> ... <DeleteBtn> <BiTrash className="delete" onClick={() => { question && dispatch(remove_question_bookmark(question)); // 2) dispatch에 액션 전달 answer && dispatch(remove_answer_bookmark(answer)); // 2) dispatch에 액션 전달 }} /> </DeleteBtn> </DetailFooter> </DetailBody> ); };
AdditionalFunc.js
- 북마크 추가하기
import { useDispatch } from 'react-redux'; import { add_answer_bookmark, add_question_bookmark, } from '../detail/bookmarkSlice'; ... export default function AdditionalFunc({ question, answer, isMyQuestion }) { const dispatch = useDispatch(); const navigate = useNavigate(); ... return ( <> {question && ( <Container> ... <Icons> <FiBookmark className="icon" onClick={() => { dispatch(add_question_bookmark(question)); // dispatch에 인자로 액션 전달 navigate('/bookmark'); }} /> </Icons>
bookmarkReducer
)으로 해당 Slice의 상태값 가져오기Bookmark.js
import { useSelector } from 'react-redux'; export default function BookmarkPage() { const bookmarks = useSelector((state) => state.bookmarkReducer); // 1) 리듀서 이름으로 해당 Slice의 상태값 가져오기 const { question_bookmarks, answer_bookmarks } = bookmarks; // 2) 상태값 객체 구조분해할당 하기 return ( <> <ContentsAndSideBox> <ContentsContainer> <Header>Question Bookmark 📚</Header> {question_bookmarks.map((question) => ( // 3) 가져온 상태값 사용하기 <BookmarkItem key={question.questionId} question={question} /> ))} <Header>Answer Bookmark 📚</Header> {answer_bookmarks.map((answer) => ( // 3) 가져온 상태값 사용하기 <BookmarkItem key={answer.answerId} answer={answer} /> ))} </ContentsContainer> <SideBox> <QuestionsSub /> </SideBox> </ContentsAndSideBox> </> ); }