Redux → React와 무관한 상태관리자
React Redux → React & Redux 통합
Redux toolkit→ Redux를 보다 수월하게 이용하게 해주는 도구
왜 태어났냐
npm install @reduxjs/toolkit
npm install react-redux
작은 store들→ slice
slice 모이면 → 큰 store
[configureStore()]
: createStore
를 감싸서 쓸만한 기본값들과 단순화된 설정을 제공합니다. 여러분의 리듀서 조각들을 자동으로 합쳐주고, 기본 제공되는 redux-thunk
를 포함해서 여러분이 지정한 미들웨어들을 더해주고, Redux DevTools 확장을 사용할 수 있게 합니다[createReducer()]
: switch 문을 작성하는 대신, 액션 타입과 리듀서 함수를 연결해주는 목록을 작성하도록 합니다. 여기에 더해 [immer
라이브러리]를 자동으로 사용해서, state.todos[3].completed = true
와 같은 변이 코드를 통해 간편하게 불변 업데이트를 할 수 있도록 합니다.[createAction()]
: 주어진 액션 타입 문자열을 이용해 액션 생산자 함수를 만들어줍니다. 함수 자체에 toString()
정의가 포함되어 있어서, 타입 상수가 필요한 곳에 사용할 수 있습니다.[createSlice()]
: 조각 이름과 상태 초기값, 리듀서 함수들로 이루어진 객체를 받아 그에 맞는 액션 생산자와 액션 타입을 포함하는 리듀서 조각을 자동으로 만들어줍니다.[createAsyncThunk]
: 액션 타입 문자열과 프로미스를 반환하는 함수를 받아, pending/fulfilled/rejected
액션 타입을 디스패치해주는 thunk를 생성해줍니다.[createEntityAdapter]
: 저장소 내에 정규화된 데이터를 다루기 위한 리듀서와 셀렉터를 만들어줍니다.[createSelector
유틸리티]를 Reselect 라이브러리에서 다시 익스포트해서 쓰기 쉽게 해줍니다.import {createSlice, configureStore} from '@reduxjs/toolkit';
const counterSlice = createSlice({
name: 'in',
initialState: {value:0},
reducers:{
up:(state,action)=>{
//state.value = state.value + action.step;
state.value = state.value + action.payload; //counterSlice.actions를 쓸때
}
}
});
//store 만들기
const store = configureStore({
reducer: { //각각의 슬라이스의 리듀서
counter: counterSlice.reducer //counterSlice안의 reducers들을 하나로 합쳐주는 하나의 reducer 생성
}
});
function Counter(){
const dispatch = useDispatch();
const count = useSelector(state=>{
return state.counter.value
});
return <div>
<button onClick={()=>
//dispatch({type:'counterSlice/up', step:2});
dispatch(counterSlice.actions.up(2)) //counterSlice.actions를 쓸때
}}>+</button> {count}
</div>
}
export default function App() {
return (
<Provider store={store}>
<div>
<Counter></Counter>
</div>
</Provider>
)
}
import { configureStore } from "@reduxjs/toolkit";
import LoginState from "./LoginSlice";
import ModalState from "./ModalSlice";
export const store = configureStore({
reducer: {
Login: LoginState.reducer, //key:value가 있는 객체 형식이어야함!
Modal: ModalState.reducer, //이때 value는 reducer가 들어옴!
},
});
export default store;
import { createSlice } from "@reduxjs/toolkit";
const initialState = {
isModal: false,
};
const ModalState = createSlice({
name: "modalstate",
initialState,
reducers: {
modalOpen: (state) => {
state.isModal = true;
},
modalClose: (state) => {
state.isModal = false;
},
},
});
export const { modalClose, modalOpen } = ModalState.actions; //reducers전달
export default ModalState;
import { createSlice } from "@reduxjs/toolkit";
const initialState = {
isLogin: false,
};
const LoginState = createSlice({
name: "loginstate",
initialState,
reducers: {
login: (state) => {
state.isLogin = true;
},
logout: (state) => {
state.isLogin = false;
},
},
});
export const { login, logout } = LoginState.actions; //reducers전달
export default LoginState;
export default function LoginModal({ isModal }) {
const dispatch = useDispatch();
const onValid = async (data) => {
try {
await axios
.post("http://localhost:3001/login", data)
.then((data) => {
closeModal();
dispatch(login()); //dispatch 적용! (전달인자는 상태 변화를 주는 action함수)
Toast.fire({
title: "로그인 성공!",
icon: "success",
customClass: {
icon: "icon-class",
container: "my-swal",
},
});
});
} catch (error) {
console.error(error);
}
};
const isLogin = useSelector((state) => state.Login.isLogin);
const isModal = useSelector((state) => state.Modal.isModal);
<ConfirmButton onClick={
isLogin? handleConfirm : () => dispatch(modalOpen())}
isModal={isModal}
>
예약하기
</ConfirmButton>