로그인 정보를 전역 상태로 사용하기 위하여 redux를 사용하기로 마음먹었다.
자연스럽게 일단 전역 상태를 저장할 store를 만들기 위해 createStore를 불러왔는데, 다음과 같은 상황에 처했다.
🥔 그리고 왜 RTK를 사용해야 하는지 적혀있는 공식문서의 주소도 안내받았다.
🥔 https://redux.js.org/introduction/why-rtk-is-redux-today
- 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>
);
- 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 된다.
import { combineReducers } from 'redux';
import user from './userSlice'; // 좀 더 직관적인 이름으로 불러와 사용한다.
const reducer = combineReducers({user});
export default reducer;
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>);
}
- 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();
console.log(user); // 불러온 전역 상태를 출력한다.
return (<S.Button onClick={() => dispatch(fetchAccount())}>계정</S.Button>
);
}