Action → Dispatch → Reducer → Store
메인 프로젝트를 진행하면서 공부했던 리덕스 툴킷 / 내 블로그 링크
이번 메인 프로젝트 때 저장소로 이용했던
리덕스 툴킷에 대해서 프로젝트와 연결해서 자세하게 공부해 보았다.
효율적으로 Redux 를 이용하기 위해 더 간단하고 쉽게 만들어짐.
configureStore()
: createStore
를 감싸서 쓸만한 기본값들과 단순화된 설정을 제공/ 리듀서 조각들을 자동으로 합쳐주고, 기본 제공되는 redux-thunk
를 포함해서 지정한 미들웨어들을 더해주고, Redux DevTools 확장을 사용할 수 있게 한다.createReducer()
: switch 문을 작성하는 대신, 액션 타입과 리듀서 함수를 연결해주는 목록을 작성하도록 함.createAction()
: 주어진 액션 타입 문자열을 이용해 액션 생산자 함수를 만듦. 함수 자체에 toString()
정의가 포함되어 있어서, 타입 상수가 필요한 곳에 사용가능createSlice()
: 조각 이름과 상태 초기값, 리듀서 함수들로 이루어진 객체를 받아 그에 맞는 액션 생산자와 액션 타입을 포함하는 리듀서 조각을 자동으로 만들어 줌.createAsyncThunk
: 액션 타입 문자열과 프로미스를 반환하는 함수를 받아, pending/fulfilled/rejected 액션 타입을 디스패치해주는 thunk를 생성해줌createEntityAdapter
: 저장소 내에 정규화된 데이터를 다루기 위한 리듀서와 셀렉터를 만들어 줌createSelector
유틸리티를 Reselect 라이브러리에서 다시 익스포트해서 쓰기 쉽게 해줌index.js
import { Provider } from 'react-redux';
import store from './app/store';
...
return (
<Provider store={store}>
<... />
</Provider>
);
...
Provider store={store}
Provider로 store를 지정해준다.
store는 말 그대로 저장소이고 이 저장소 안에는 여러개의 slice들로 이루어져 있음.
(property
의 명이 반드시 reducer
!! 그리고 createStore와 달리 ! Thunk, dev tool
까지 자동 등록)
import { configureStore } from '@reduxjs/toolkit';
import goalCreateSlice from '../reducer/goalCreateSlice';
// 전역 저장소 설정
const store = configureStore({
reducer: {
goalCreate: goalCreateSlice,
...
},
});
export default store;
먼저 스토어 생성! (const store~) [공식문서]
configureStore
:createStore와 달리, 여러 개의 인자 대신에 이름이 지정된 하나의 object를 받고 -> reducer
을 넘겨준다
Slice
를 만들어줘서 action, reducer
을 동시에 써 줌 (밑에)
정의한 스테이트들을 반환
reducer 함수와 action creator 를 포함한 객체
name
: 해당 모듈의 이름을 작성initialState
: 해당 모듈의 초기값 세팅reducers
: 리듀서를 작성. 이때 해당 리듀서의 키값으로 액션함수가 자동으로 생성extraReducers
: 액션함수가 자동으로 생성되지 않는 별도의 액션함수가 존재하는 리듀서를 정의goalCreateSlice.js
import { createSlice } from '@reduxjs/toolkit';
const initGoalPrice = {
goalName: '',
price: '',
monthlyPayment: '',
url: '',
};
const initialState = { data: initGoalPrice };
// 로그인, 로그아웃 리듀서 설정 => 로그인 상태 변경 및 유저 정보 추가 or 초기화
const goalCreateSlice = createSlice({
name: 'goalCreate',
initialState,
reducers: {
setGoalCreate: (state, action) => {
state.data = { ...state.data, ...action.payload };
},
setGoalCreateInit: (state) => {
state.data = initGoalPrice;
},
},
});
export const { setGoalCreate, setGoalCreateInit } = goalCreateSlice.actions;
export default goalCreateSlice.reducer;
reducer
을 리턴해줌으로써
슬라이스에 제공된 초기 상태 값에 대한 액세스를 제공 &
지연 상태 초기화가 제공되면 호출되고 새로운 값이 반환
redux의 액션 함수를 실행해서 redux store에 변경된 state값을 저장하기 위해서
useDispatch
라는 리액트 훅을 사용하여 액션을 실행
dispatch를 이용 -> 액션 함수 실행 -> state
저장 & 변경
등록한 데이터를 가져와서 쓸 수 있다
Components/goalSetting.js
import { useDispatch, useSelector } from 'react-redux';
import { setGoalCreate } from '../../reducer/goalCreateSlice';
const AssetSetting = ({ goalPost }) => {
const goalData = useSelector((state) => state.goalCreate);
const dispatch = useDispatch();
const setInputChange = (e) => {
const result = {};
result[e.target.name] = e.target.value;
dispatch(setGoalCreate(result));
};
return (
...
pages/goalCreate.js
const GoalCreatePage = () => {
const navigate = useNavigate();
const dispatch = useDispatch();
const goalData = useSelector((state) => state.goalCreate);
const { enqueueSnackbar } = useSnackbar();
useEffect(() => {
dispatch(setGoalCreateInit());
}, []);
const goalPost = () => {
const postdata = {
goalName: goalData.data.goalName,
price: goalData.data.price,
monthlyPayment: goalData.data.monthlyPayment,
url: goalData.data.url,
};
// console.log(postdata.url);
axios
.post(getURL_GOALS(), postdata, getWITH_TOKEN())
.then(() => {
Swal.fire({
text: '목표가 등록되었어요!',
icon: 'success',
});
setGoalCreateInit(); //useState 이용했던 것
navigate('/goalList');
})
.catch((error) => {
const { message } = error;
enqueueSnackbar(getERROR_TEXT(Number(message.slice(-3))), {
variant: 'error',
});
});
};
pages/goalCreate.js
const GoalCreatePage = () => {
const navigate = useNavigate();
const [goal, setGoal] = useState(''); // 수기 목표 이름
const [goalPrice, setGoalPrice] = useState(''); // 수기 가격
const [monthPrice, setMonthPrice] = useState(''); // 수기 한 달 입금
const handlerGoal = (e) => {
setGoal(e.target.value);
};
const handlerGoalPrice = (e) => {
setGoalPrice(e.target.value);
};
const handlerMonthPrice = (e) => {
setMonthPrice(e.target.value);
};
const goalPost = () => {
const postdata = {
goalName: goal,
price: goalPrice,
monthlyPayment: monthPrice,
};
axios
.post(getURL_GOALS(), postdata, getWITH_TOKEN())
.then((response) => {
const { data } = response;
console.log(data);
Swal.fire({
text: '목표가 등록되었어요!',
icon: 'success',
});
setGoal('');
setGoalPrice('');
setMonthPrice('');
navigate('/goalList');
})
.catch((error) => {
console.log(error);
});
};
return (
...
리덕스 툴킷 사용하면서도 정리를 안해놔서 머릿 속이 뒤죽박죽이었는데 이 글 보고 그나마 정리가 되네요!