import { createStore, combineReducers } from "redux";
import todo from "./modules/todo";
const rootReducer = combineReducers({ todo });
const store = createStore(rootReducer);
내가 만든 투두리스트에 기본 리덕스 버젼의 store이다.
이걸
import {configureStore} from "@reduxjs/toolkit"
import todoSlice from './modules/todoSlice';
const store = configureStore({
reducer:{
todo : todoSlice
}})
export default store;
요렇게 바꾼다.
createStore와 configureStore의 차이로는
combinereducer, thunk, applyMiddelware, composeWithDevTools가 자동으로 들어가있다.
모듈안에서는 다음과 같이 바뀌었다.
기본
// Actions
// const CREATE = "todo/CREATE";
// const UPDATE = "todo/UPDATE";
// const DELETE = "todo/DELETE";
// const initinalState = [
// {
// id: 1,
// Done: true,
// title: "리액트하기",
// todoDesc: "리액트 기초를 익혀봅시다",
// },
// {
// id: 2,
// Done: false,
// title: "라우터",
// todoDesc: "라우터 기초를 익혀봅시다",
// },
// {
// id: 3,
// Done: false,
// title: "리덕스",
// todoDesc: "리덕스 기초를 익혀봅시다",
// },
// ];
// Action Creators
// export function createTodo(todolist) {
// return { type: CREATE, todolist };
// }
// export function updateTodo(todo_id) {
// return { type: UPDATE, todo_id };
// }
// export function deleteTodo(todo_id) {
// return { type: DELETE, todo_id };
// }
// Reducer
// export default function reducer(state = initinalState, action = {}) {
// switch (action.type) {
// case "todo/CREATE": {
// const new_todolist = [...state, action.todolist];
// return new_todolist;
// }
// case "todo/UPDATE": {
// const new_todolist = state.map((x) => {
// if (x.id === parseInt(action.todo_id)) {
// return { ...x, Done: !x.Done };
// } else {
// return x;
// }
// });
// return new_todolist;
// }
// case "todo/DELETE": {
// const new_todolist = state.filter((x) => {
// return x.id !== parseInt(action.todo_id);
// });
// return new_todolist;
// }
// default:
// return state;
// }
// }
이거가
import { createSlice } from '@reduxjs/toolkit';
const todoSlice =createSlice({
name: 'todo',
initialState: [ {
id: 1,
Done: true,
title: "리액트하기",
todoDesc: "리액트 기초를 익혀봅시다",
},
{
id: 2,
Done: false,
title: "라우터",
todoDesc: "라우터 기초를 익혀봅시다",
},
{
id: 3,
Done: false,
title: "리덕스",
todoDesc: "리덕스 기초를 익혀봅시다",
}],
reducers :{
createTodo : (state,action)=>{
state.push(action.payload)
},
updateTodo : (state,action)=>{
console.log(action)
const idx = state.findIndex((x) => {
return x.id === action.payload;
});
state[idx].Done = !state[idx].Done
},
deleteTodo : (state,action)=>{
const idx = state.findIndex((x) => {
return x.id === action.payload;
});
state.splice(idx,1)
}
}
})
export const {createTodo,updateTodo,deleteTodo} = todoSlice.actions;
export default todoSlice.reducer
이렇게 간결하게 바뀌었다.
기본 요소로 name,initialState, reducers 세가지가 있고
name은 그냥 이 함수에 맞는 이름을 지어주자
나머지는 기본 리덕스에서 나타내는것과 같다.
다른점으로 리듀서에서 값을 새로운 객체를 반환할 필요가 없는데 그것은 immer가 알아서 불변성 유지를 해준다.(JS의 proxy라는 객체를 이용하여 불변성을 유지한다.)
추가적으로 FB를 추가하면 어떻게 바뀌는지도 살펴보자
이전의 코드
// import { async } from "@firebase/util";
// import {
// collection,
// doc,
// getDoc,
// getDocs,
// addDoc,
// updateDoc,
// deleteDoc,
// } from "firebase/firestore";
// import { db } from "../../firebase";
// // Actions
// const LOAD = "bucket/LOAD";
// const CREATE = "bucket/CREATE";
// const DELETE = "bucket/DELETE";
// const UPDATE = "bucket/UPDATE";
// const initialState = {
// list: [],
// };
// // Action Creators
// export function loadBucket(BucketList) {
// return { type: LOAD, BucketList };
// }
// export function createBucket(bucket) {
// return { type: CREATE, bucket };
// }
// export function updateBucket(datas) {
// return { type: UPDATE, datas };
// }
// export function deleteBucket(bucket) {
// return { type: DELETE, bucket };
// }
// //FB creator
// export const loadBucketFB = () => {
// return async function (distpatch) {
// const bucket = await getDocs(collection(db, "bucket"));
// let bucket_list = [];
// bucket.forEach((x) => {
// bucket_list.push({ id: x.id, ...x.data() });
// });
// distpatch(loadBucket(bucket_list));
// };
// };
// export const createBucketFB = (bucket) => {
// return async function (dispatch) {
// const docRef = await addDoc(collection(db, "bucket"), bucket);
// const _bucket = await getDoc(docRef);
// const bucket_data = { id: docRef.id, ..._bucket.data() };
// // const adasd = {id docRef, ...bucket}
// dispatch(createBucket(bucket_data));
// };
// };
// export const updateBucketFB = (bucket) => {
// return async function (dispatch, getState) {
// const docRef = doc(db, "bucket", bucket);
// const isDone = getState().bucket.list.filter((x) => {
// return x.id === bucket;
// })[0].Done;
// console.log(isDone);
// await updateDoc(docRef, { Done: !isDone });
// dispatch(updateBucket(bucket));
// };
// };
// export const deleteBucketFB = (bucket) => {
// return async function (dispatch) {
// const docRef = doc(db, "bucket", bucket);
// await deleteDoc(docRef);
// dispatch(deleteBucket(bucket));
// };
// };
// // Reducer
// export default function reducer(data = initialState, action = {}) {
// switch (action.type) {
// case "bucket/LOAD": {
// return { list: action.BucketList };
// }
// case "bucket/CREATE": {
// const new_bucket_list = [...data.list, action.bucket];
// return { list: new_bucket_list };
// }
// case "bucket/UPDATE": {
// const isDone = data.list.filter((x) => {
// return x.id === action.datas;
// })[0].Done;
// const new_bucket_list = data.list.map((x) => {
// if (action.datas === x.id) {
// return { ...x, Done: !isDone };
// } else {
// return x;
// }
// });
// return { list: new_bucket_list };
// }
// case "bucket/DELETE": {
// const new_list = data.list.filter((x) => {
// return action.bucket !== x.id;
// });
// return { list: new_list };
// }
// default:
// return data;
// }
// }
총 114줄에 달하는 길이이다
여기서 createSlice를 쓴다면 그저 원래 리듀서 부분을 조금만 손봐주고 FB함수들은 그대로 두면된다.
import { createSlice } from '@reduxjs/toolkit';
import {
collection,
doc,
getDoc,
getDocs,
addDoc,
updateDoc,
deleteDoc,
} from "firebase/firestore";
import { db } from "../../firebase";
//FB creator
export const loadBucketFB = () => {
return async function (distpatch) {
const bucket = await getDocs(collection(db, "bucket"));
let bucket_list = [];
bucket.forEach((x) => {
bucket_list.push({ id: x.id, ...x.data() });
});
distpatch(loadBucket(bucket_list));
};
};
export const createBucketFB = (bucket) => {
return async function (dispatch) {
const docRef = await addDoc(collection(db, "bucket"), bucket);
const _bucket = await getDoc(docRef);
const bucket_data = { id: docRef.id, ..._bucket.data() };
// const adasd = {id : docRef.id, ...bucket}
dispatch(createBucket(bucket_data));
};
};
export const updateBucketFB = (bucket) => {
return async function (dispatch, getState) {
const docRef = doc(db, "bucket", bucket);
const isDone = getState().bucket.list.filter((x) => {
return x.id === bucket;
})[0].Done;
console.log(isDone);
await updateDoc(docRef, { Done: !isDone });
dispatch(updateBucket(bucket));
};
};
export const deleteBucketFB = (bucket) => {
return async function (dispatch) {
const docRef = doc(db, "bucket", bucket);
await deleteDoc(docRef);
dispatch(deleteBucket(bucket));
};
};
const bucket = createSlice({
name : "bucket",
initialState:{
list: [],
},
reducers :{
loadBucket : (state,action)=>{
state.list = action.payload
},
createBucket :(state,action)=>{
state.list.push(action.payload)
},
updateBucket : (state,action)=>{
const idx = state.list.findIndex(x=>{
return x.id === action.payload
})
state.list[idx].Done =!state.list[idx].Done
},
deleteBucket : (state,action)=>{
const idx = state.list.findIndex((x) => {
return x.id === action.payload;
});
state.list.splice(idx,1)
},
}
})
export const { loadBucket,createBucket,updateBucket,deleteBucket} = bucket.actions
export default bucket.reducer
85줄로 1/4이 줄어들었다.
그리고 위에서 말했듯이 combinereducer, thunk, applyMiddelware, composeWithDevTools가 자동으로 들어가있어서 configStore.js의 코드도 줄어든다.
// import { createStore, combineReducers, applyMiddleware, compose } from "redux";
// import bucket from "./modules/bucket";
// import thunk from "redux-thunk";
// const middlewares = [thunk];
// const rootReducer = combineReducers({ bucket });
// const enhancer = applyMiddleware(...middlewares);
// const store = createStore(rootReducer, enhancer);
// export default store;
에서
import {configureStore} from "@reduxjs/toolkit"
import bucket from './modules/bucketSlice';
const store = configureStore({
reducer:{
bucket : bucket
}})
export default store;
로 변경되었다.