React
Redux Toolkit (rtk) 사용하기
citron031
2022. 11. 4. 08:53
- 로그인 정보를 전역 상태로 사용하기 위하여 redux를 사용하기로 마음먹었다.
- 자연스럽게 일단 전역 상태를 저장할 store를 만들기 위해 createStore를 불러왔는데, 다음과 같은 상황에 처했다.
- 커서를 createStore에 대고 읽은 안내 메세지에 따르면, createStore는 deprecated되었고 그 대신에 @reduxjs/toolkit의 configureStore메소드를 사용하는 것을 추천받았다.
🥔 그리고 왜 RTK를 사용해야 하는지 적혀있는 공식문서의 주소도 안내받았다.
🥔 https://redux.js.org/introduction/why-rtk-is-redux-today
Why Redux Toolkit is How To Use Redux Today | Redux
Introduction > Why RTK is Redux Today: details on how RTK replaces the Redux core
redux.js.org
- 이제는 redux를 사용하는데 Redux Toolkit가 필수적인 요소가 되었고, 나 역시 Redux Toolkit을 사용하여 redux를 세팅하기로 하였다.
configureStore
createStore 대신에 사용하게 될 configureStore이다.
store를 만들고, Provider로 연결해준다.
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reducer from './redux/reducer';
import { Provider } from 'react-redux';
import { configureStore } from '@reduxjs/toolkit';
const store = configureStore({reducer})
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<Provider store={store}>
<App/>
</Provider>
</React.StrictMode>
);
createSlice
action과 reducer를 손쉽게 만들어주는 매소드이다.
reducer만 작성하면, 자동으로 action을 만들어준다.
import { createSlice } from "@reduxjs/toolkit";
const userSlice = createSlice({
name: "user",
initialState: {
nickname: "",
error: ""
},
reducers: {
setNickname: (state, action) => {
state.nickname = action.payload;
},
},
extraReducers: {},
});
export const { setNickname } = userSlice.actions; // action 생성
export default userSlice.reducer; // reducer가 export 된다.
- 생성된 reducer를 연결해주도록 한다.
import { combineReducers } from 'redux';
import user from './userSlice'; // 좀 더 직관적인 이름으로 불러와 사용한다.
const reducer = combineReducers({user});
export default reducer;
- hook을 이용하여 전역 상태를 사용한다.
import { useSelector, useDispatch } from "react-redux";
import { setNickname } from '../redux/userSlice';
export const component = () => {
const user = useSelector(state => state.user);
const dispatch = useDispatch();
console.log(user); // 불러온 전역 상태를 출력한다.
return (<button onClick={() => dispatch(setNickname("새이름"))}>클릭!</button>);
}
- 버튼이 클릭되면, 전역상태 nickname이 초기 값 ""에서 "새이름"으로 변경된다.
createAsyncThunk
Redux Toolkit를 사용하고 있다면, 비동기 처리를 위해서 react-thunk를 설치할 필요가 없다.
🧀 Redux Toolkit은 thunk를 내장한다.Redux Toolkit을 통해서 비동기 처리를 하고자 한다면, createAsyncThunk 매서드를 사용하도록 하자.
import { createAsyncThunk, createSlice } from "@reduxjs/toolkit";
export const fetchAccount = createAsyncThunk("account/getUser", async () => {
return fetch(url).then(el => el.json()).catch(err => err);
});
const userSlice = createSlice({
name: "user",
initialState: {
nickname: "",
account: "",
isLodaing: false,
error: "",
},
reducers: {
setNickname: (state, action) => {
state.nickname = action.payload;
},
},
extraReducers: (builder) => {
builder
.addCase(fetchAccount.pending, (state, action) => {
state.isLodaing = true; // 로딩중
state.account = "";
})
.addCase(fetchAccount.fulfilled, (state, action) => {
state.isLodaing = false;
state.account = action.payload;
})
.addCase(fetchAccount.rejected, (state, action) => {
state.isLodaing = false;
state.error = action.error;
})
},
});
export default userSlice.reducer;
- Promise 값을 리턴하는 비동기 함수가 필요하다. (위의 코드에서는 fetchAccount)
- extraReducers에 builder를 사용하여, reducer를 작성한다.
- addCase를 통해서 각 Promise의 상태마다 어떤 값을 처리할지 설정한다.
import { useSelector, useDispatch } from "react-redux";
import { fetchAccount } from '../redux/userSlice';
export const component = () => {
const user = useSelector(state => state.user);
const dispatch = useDispatch();
const onClickButton = async () => {
await dispatch(fetchAccount());
console.log("FETCH END!");
}
console.log(user); // 불러온 전역 상태를 출력한다.
return <S.Button onClick={onClickButton}>계정</S.Button>;
}
- 따로 action을 반환하지 않고, createAsyncThunk로 만든 비동기 함수가 사용된다.
- createAsyncThunk를 사용하면, dispatch에서도 async await 문법을 사용할 수 있다.