redux-toolkit적용과 persist 적용

gusdas·2022년 5월 8일
1

에러노트

목록 보기
3/22
post-thumbnail
post-custom-banner

파일구조

toolkit만 적용했을때 파일구조

toolkit, persist 적용했을 때 파일구조

공식문서대로 toolkit만 적용했을 때

// redux/store.js
import { configureStore, combineReducers } from '@reduxjs/toolkit';
import logger from 'redux-logger';

import testReducer from '../redux/slice/testSlice';
import postReducer from '../redux/slice/postSlice';

const rootReducer = combineReducers({
  test: testReducer,
  post: postReducer,
});

export const store = configureStore({
  reducer: rootReducer,
  //   middleware: [logger],
});

persist적용 코드

// redux/store/index.js
import {configureStore, combineReducers} from '@reduxjs/toolkit';
import {
  persistStore,
  persistReducer,
  FLUSH,
  REHYDRATE,
  PAUSE,
  PERSIST,
  PURGE,
  REGISTER,
} from 'redux-persist';
import storage from 'redux-persist/lib/storage';
import logger from 'redux-logger';

import testReducer from 'redux/slice/testSlice';
import postReducer from 'redux/slice/postSlice';

const persistConfig = {
  key: 'root',
  version: 1,
  storage,
};

const rootReducer = combineReducers({
  test: testReducer,
  post: postReducer,
});

const persistedReducer = persistReducer(persistConfig, rootReducer);

const store = configureStore({
  reducer: persistedReducer,
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware({
      serializableCheck: {
        ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER],
      },
      // }).concat(logger),
    }),
});
export const persistor = persistStore(store);
export default store;

공식문서 counterSlice testSlice로 변경

// redux/slice/testSlice.js
import {createSlice} from '@reduxjs/toolkit';

const initialState = {
  value: 0,
};
const testSlice = createSlice({
  name: 'counter',
  initialState,
  reducers: {
    increment: (state) => {
      state.value += 1;
    },
    decrement: (state) => {
      state.value -= 1;
    },
    incrementByAmount: (state, action) => {
      state.value += action.payload;
    },
  },
});

// Action creators are generated for each case reducer function
export const testActions = testSlice.actions;

export default testSlice.reducer;

thunkAction에서 postSlice로 dispatch하는 reducer

// redux/slice/postSlice.js 
import {createSlice} from '@reduxjs/toolkit';

const initialState = {
  posts: [],
};

const postSlice = createSlice({
  name: 'post',
  initialState,
  reducers: {
    setPost: (state, action) => {
      state.posts = action.payload;
    },
  },
});

// Action creators are generated for each case reducer function
export const postActions = postSlice.actions;

export default postSlice.reducer;

thunkAction

// redux/thunkActions/postsActions.js
import {postActions} from 'redux/slice/postSlice';
import postAPI from 'api/postAPI';

//미들웨어
const getPostAPI = () => {
  return async function (dispatch) {
    const response = await postAPI.postsAxios();
    dispatch(postActions.setPost(response.posts));
  };
};

const postsActions = {getPostAPI};

export default postsActions;

API요청

import axios from 'axios';

//인스턴스 생성
const apiClicent = axios.create({
  baseURL: 'ip주소',
});

//게시글 목록 전체 조회
const postsAxios = async () => {
  try {
    const res = await apiClicent.get('posts');
      return res;
    
  } catch (error) {
    console.error(error);
  }
};

const postAPI = {
  postsAxios,
};

export default postAPI;

app.js

import React from 'react';
import {BrowserRouter, Routes, Route} from 'react-router-dom';
import {PersistGate} from 'redux-persist/integration/react';
import store, {persistor} from 'redux/store';
import {Provider} from 'react-redux';

import AppWrapper from 'components/common/AppWrapper';
import Auth from 'pages/auth';
import Party from 'pages/party';
import TestPage from 'pages/TestPage';

const App = () => {
  return (
    <Provider store={store}>
      <PersistGate loading={null} persistor={persistor}>
        <AppWrapper>
          <BrowserRouter>
            <Routes>
              <Route path="/auth/*" element={<Auth />} />
              <Route path="/party/*" element={<Party />} />

              <Route path="/test" element={<TestPage />} />
            </Routes>
          </BrowserRouter>
        </AppWrapper>
      </PersistGate>
    </Provider>
  );
};

export default App;

dispatch하는 곳

//testPage.js 
import React from 'react';
import {useSelector, useDispatch} from 'react-redux';
import {testActions} from 'redux/slice/testSlice';
import postsActions from 'redux/thunkActions/PostsAction';

function TestPage() {
  const count = useSelector((state) => state.test.value);
  const post = useSelector((state) => state.post);
  const dispatch = useDispatch();
  console.log(post.posts);

  return (
    <>
      <button
        aria-label="Increment value"
        onClick={() => dispatch(testActions.increment())}>
        Increment
      </button>
      <span>{count}</span>
      <button
        aria-label="Decrement value"
        onClick={() => dispatch(testActions.decrement())}>
        Decrement
      </button>
      <span></span>
      {post.posts.map((post, idx) => (
        <div key={idx}>{post.content}</div>
      ))}
      <button onClick={() => dispatch(postsActions.getPostAPI())}>
        요청하기
      </button>
      <div>hi</div>
    </>
  );
}

export default TestPage;

결과

새로고침 해도 값이 있다.

전체코드 보기

전체코드 보기

참고자료

공식문서: https://redux-toolkit.js.org/usage/usage-guide
npm 문서: https://www.npmjs.com/package/reduxjs-toolkit-persist#redux-toolkit-usage

많은 도움이 된 자료: https://medium.com/geekculture/redux-persist-redux-toolkit-implementation-made-easy-for-react-native-and-react-js-831ee1e3f22b

한글 리덕스에 persist적용:https://velog.io/@tunakim/Redux-Persist-%EC%82%AC%EC%9A%A9%ED%95%98%EC%97%AC-Store-%EC%9C%A0%EC%A7%80%ED%95%98%EA%B8%B0

profile
웹개발자가 되자
post-custom-banner

4개의 댓글

comment-user-thumbnail
2022년 6월 14일

감사합니다 ! 많은 도움이 되었습니당

1개의 답글
comment-user-thumbnail
2023년 2월 3일

폴더 구조 및 redux-persist 설정하는 데에 많은 도움이 되었습니다.

1개의 답글