import { createStore } from "redux";
import { combineReducers } from "redux";
import workoutReducer from "redux/reducers/workout";
import menuReducer from "redux/reducers/menu";
const rootReducer = combineReducers({ workoutReducer, menuReducer });
const store = createStore(rootReducer);
export default store;
우선 필요한 Redux를 세팅해준다.
combineReducers
로 리듀서들을 묶어주고, createStore
로 store를 생성한다.
import dummy from "../../fakedata.json";
//action values
export const ADD = "workout/ADD";
export const DELETE = "workout/DELETE";
export const MODIFY = "workout/MODIFY";
//action creators
export const addItem = (payload) => {
return {
type: ADD,
payload,
};
};
export const deleteItem = (id) => {
return {
type: DELETE,
payload: id,
}
}
export const modifyItem = (payload) => {
return {
type: MODIFY,
payload,
}
}
//inital state
const initialState = dummy;
const workoutReducer = (state = initialState, action) => {
switch (action.type) {
case ADD:
return [...state, action.payload];
case DELETE:
return state = state.filter(s => s.id !== action.payload);
case MODIFY:
{
const filteredData = state.filter(s => s.id !== action.payload.id)
return [...filteredData, action.payload]
}
default:
return state;
}
};
export default workoutReducer;
CRUD에 필요한 reducer
를 작성한다.
action values
와 action creators
를 만들어 휴먼에러를 예방한다.
후에 컴포넌트에서 action creator
를 dispatch
하여 사용할 것이기 때문에 action creators
의 return값은 객체로 설정한다.
우리는 state를 업데이트 할 것이기 때문에 리듀서 함수는 항상 state를 업데이트 하여야 한다.
// add item
import { useDispatch } from "react-redux";
import { addItem } from "redux/reducers/workout";
const Form = () => {
const dispatch = useDispatch(); // action을 dispatch하기 위한 useDispatch 선언
const [nickname, setNickname] = useState("");
const [content, setContent] = useState("");
const [workout, setWorkout] = useState("스쿼트");
const nicknameHandler = (e) => {
setNickname(e.target.value);
};
const contentHandler = (e) => {
setContent(e.target.value);
};
const workoutHandler = (e) => {
setWorkout(e.target.value);
};
const submitHandler = (e) => {
e.preventDefault();
const data = {
createdAt: new Date().toISOString(),
nickname,
avatar: "https://static.vecteezy.com/system/resources/previews/009/292/244/original/default-avatar-icon-of-social-media-user-vector.jpg",
content,
writedTo: workout,
id: uuid(),
};
if (nickname.trim() === "") {
alert("Please enter a nickname");
return;
}
if (content.trim() === "") {
alert("Please enter a content");
return;
}
dispatch(addItem(data)); // reducer로 action dispatch
setNickname("");
setContent("");
}; // 편의상 코드 생략
// delete item & modify item
import { useDispatch, useSelector } from 'react-redux';
import { deleteItem, modifyItem } from 'redux/reducers/workout';
const FanLetter = () => {
const dispatch = useDispatch(); // action을 dispatch하기 위한 useDispatch 선언
const workoutData = useSelector(state => state.workoutReducer); // useSelector로 현재 state 가져오기
const { id } = useParams();
const filteredData = workoutData.filter((w) => w.id === id)[0];
const [isModifyBtnClicked, setIsModifyBtnClicked] = useState(false);
const [modifyText, setModifyText] = useState(filteredData.content);
const data = {
createdAt: filteredData.createdAt,
nickname: filteredData.nickname,
avatar: filteredData.avatar,
content: modifyText,
writedTo: filteredData.writedTo,
id: filteredData.id,
};
const navigate = useNavigate();
const navigateHandler = () => {
navigate("/");
};
const deleteWorkoutHandler = (id) => {
if (window.confirm("삭제하시겠습니까?")) {
dispatch(deleteItem(id));
navigateHandler();
}
};
const modifyHandler = () => {
setIsModifyBtnClicked(!isModifyBtnClicked);
};
const textModifyHandler = (e) => {
setModifyText(e.target.value);
};
const textModifyConfirmHandler = (e) => {
if (window.confirm("수정하시겠습니까?")) {
if (modifyText.trim() === "") {
alert("내용을 채워주세요");
return;
}
if (filteredData.content === modifyText) {
alert("변경된 내용이 없습니다.");
return;
}
dispatch(modifyItem(data)); // action dispatch
setIsModifyBtnClicked(!isModifyBtnClicked);
navigateHandler();
}
}; // 편의상 코드 생략
이제 우리는 useDispatch
를 통해 action
을 리듀서 함수(store)로 보낼 수 있다.
또한 useSelector
로 리듀서의 현재 state를 불러올 수 있다.