진짜 진짜 까먹을까봐 적는 RTK(Redux Toolkikt), Redux-persist
# with npm
npm install @reduxjs/toolkit react-redux
# with yarn
yarn add @reduxjs/toolkit react-redux
src
│
├── store
│ ├── store.ts // 저장소
│ ├── features // 기능 폴더
│ └───── authSlice.ts // 기능 Slice
├── components
│ ├── Profile.tsx
│ └── ...
main.tsx
...
/* authSlice.ts */
import { createSlice } from '@reduxjs/toolkit'; // reducer 만드는 걸 도와줌
const initialState = { // 초기 상태
nickname: '',
email: '',
accessToken: '',
refreshToken: '',
};
export const authSlice = createSlice({ // name, initialState, reducers 필수 값
name: 'auth',
initialState: {
value: initialState,
},
reducers: { // state 변경 메소드들
login: (state, action) => {
state.value = { ...state.value, ...action.payload };
},
logout: (state) => {
state.value = initialState;
},
},
});
export const { login, logout } = authSlice.actions;
export default authSlice.reducer;
// createSlice는 객체를 return 하고 return 된 값들 중 reducer를 export 해야 함
store.ts
를 생성하여 저장소를 만들어준다/* store.ts */
import { configureStore } from '@reduxjs/toolkit';
import authReducer from './features/auth/authSlice';
const store = configureStore({
reducer: {
auth: authReducer, // 앞서 export 했던 reducer를 auth라는 이름으로 저장
},
});
export default store;
export type RootState = ReturnType<typeof store.getState>;
// typescript 이기 때문에 RootState type을 export 해야 함
/* main.tsx */
import ReactDOM from 'react-dom/client';
import './index.css';
import { RouterProvider } from 'react-router-dom';
import router from './routes/Router';
import { Provider } from 'react-redux'; // Provider import
import store from './store/store'; // store import
ReactDOM.createRoot(document.getElementById('root')!).render(
<Provider store={store}> // root를 Provider로 감싼 후 store 넘겨주기
<RouterProvider router={router} />,
</Provider>
);
/* Profile.tsx */
import { useDispatch, useSelector } from 'react-redux';
// useDispatch : state 변경 메소드를 이용하여 store에 있는 state 변경
// useSelector : store에 있는 원하는 state 가져옴
import { type RootState } from '../store/store';
// 앞서 store.ts에서 export한 type import
import { logout } from '../store/features/authSlice';
// 앞서 authSlice.ts에서 export한 state 변경 메소드 import
export default function Profile() {
const dispatch = useDispatch();
const user = useSelector((state: RootState) => state.auth.value);
return (
<div>
<p>nickname: {user.nickname}</p>
<p>email: {user.email}</p>
<button onClick={() => dispatch(logout())}>로그아웃</button>
</div>
);
}
store에 저장된 state를 storage에 저장하기 위해 redux-persist를 사용했다.
다들 RTK에 redux-persist을 적용하는 걸 너무 어렵게 설명해놨는데 진짜 별거 아님
위에서 작성한 store.ts
에 아래 코드 중 주석 달린 부분만 추가해주면 됨
import { configureStore, combineReducers } from '@reduxjs/toolkit';
import authReducer from './features/authSlice';
import { persistReducer } from 'redux-persist'; // 추가
import storage from 'redux-persist/lib/storage'; // 추가, default : localStorage
// Session → import storageSession from 'redux-persist/lib/storage/session
const rootReducer = combineReducers({
auth: authReducer,
});
// ↑ 추가 ❶
// store.ts에서 reducer에 작성했던 것들을 빼내어 combineReducers에 작성
const persistConfig = {
key: 'auth', // storage에 저장될 key 입력
storage, // 저장될 위치 입력
whitelist: ['auth'], // 저장할 state 입력
};
// ↑ 추가 ❷
const persistedReducer = persistReducer(persistConfig, rootReducer);
// ↑ 추가
// persistReducer에 앞서 작성한 ❶, ❷를 인자로 넘김
const store = configureStore({
reducer: persistedReducer,
// ↑ 수정
// 앞서 작성한 persistedReducer로 값 수정
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({
serializableCheck: false,
}),
// ↑ 에러 때문에 추가했음, 필수 아님
});
export default store;
export type RootState = ReturnType<typeof store.getState>;
이렇게 유용한 정보를 공유해주셔서 감사합니다.