JS/React

React - 로그인 정보 관리(Redux 사용)

shin96bc 2024. 3. 9. 18:03

프로세스

Redux에 로그인 정보를 담아서 전역적으로 사용할 수 있도록 합니다.

 

상태를 관리하는 Store가 따로 존재합니다.

 

코드 작성법

폴더 구조

 

store

  • LoginDataSlice.js
import { createSlice } from "@reduxjs/toolkit";

const initialState = {
  token: '',
  name: '',
  isValidToken: false
};

const LoginDataSlice = createSlice({
  name: 'loginData',
  initialState,
  reducers: {
    login(state, action) {
      return {...initialState, ...action.payload, isValidToken: true};
    },
    logout(state) {
      state.token = '';
      state.name = '';
      state.isValidToken = false;
    },
    tokenExpired(state) {
      state.isValidToken = false;
    }
  }
});

export const {login, logout, tokenExpired} = LoginDataSlice.actions;

export default LoginDataSlice.reducer;
  • index.js
import { combineReducers } from 'redux';
import { configureStore } from "@reduxjs/toolkit";
import loginDataSlice from "./slices/LoginDataSlice";

const reducers = combineReducers({
  loginData: loginDataSlice,
});

const store = configureStore({
  reducer: reducers,
  // state에 function을 사용하기 위해 선언
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware({
      serializableCheck: false
    })

});

export default store;

 

App.js

import PrivateRoutes from "./routes/private";
import PublicRoutes from "./routes/public";
import { useSelector } from "react-redux";

function App() {

  const {isValidToken} = useSelector((state) => state.loginData);

  return (
    <>
      {
        isValidToken ?
          <PrivateRoutes />
          :
          <PublicRoutes />
      }

    </>
  );
}

export default App;

 

 

index.js

import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { BrowserRouter } from "react-router-dom";
import { Provider } from "react-redux";
import store from "./store";


const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <Provider store={store}>
    <BrowserRouter>
      <App/>
    </BrowserRouter>
  </Provider>
);

reportWebVitals();

 

localStorage를 사용하는 경우

redux-persist 설치

yarn add redux-persist

or

npm install redux-persist

store

  • slices
    • LoginDataSlice.js
import { createSlice } from "@reduxjs/toolkit";

const initialState = {
  token: '',
  name: '',
  isValidToken: false
};

const LoginDataSlice = createSlice({
  name: 'loginData',
  initialState,
  reducers: {
    login(state, action) {
      return {...initialState, ...action.payload, isValidToken: true};
    },
    logout(state) {
      state.token = '';
      state.name = '';
      state.isValidToken = false;
    },
    tokenExpired(state) {
      state.isValidToken = false;
    }
  }
});

export const {login, logout, tokenExpired} = LoginDataSlice.actions;

export default LoginDataSlice.reducer;
  • index.js
import { combineReducers } from 'redux';
import { configureStore } from "@reduxjs/toolkit";
import loginDataSlice from "./slices/LoginDataSlice";
import storage from 'redux-persist/lib/storage';
import LoginDataSlice from "./slices/LoginDataSlice";
import { persistReducer, persistStore } from "redux-persist";

// persistReducer를 전체 reducer가 들어있는 reducers를 기준으로 사용하면 whitelist, blacklist는 reducer(slice) name이다.
const rootPersistConfig = {
  key: 'root',
  storage,
  blacklist: ["loginData"], // reducer name
}

// persistReducer를 특정 reducer에 사용하면 whitelist, blacklist는 reducer안에 state name 이다.
const persistConfig = {
  key: 'login',
  storage,
  whitelist: ["token", "name"], // state name
};

const reducers = combineReducers({  
  loginData: persistReducer(persistConfig, loginDataSlice), // 특정 state를 지정한 per
});

const store = configureStore({
  reducer: persistReducer(rootPersistConfig, reducers), // 특정 reducer를 지정한 persist
  // state에 function을 사용하기 위해 선언
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware({
      serializableCheck: false
    })

});

export const persist = persistStore(store);

export default store;

 

App.js

import PrivateRoutes from "./routes/private";
import PublicRoutes from "./routes/public";
import { useSelector } from "react-redux";

function App() {

  const {isValidToken} = useSelector((state) => state.loginData);

  return (
    <>
      {
        isValidToken ?
          <PrivateRoutes />
          :
          <PublicRoutes />
      }

    </>
  );
}

export default App;

 

index.js

import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import reportWebVitals from './reportWebVitals';
import {BrowserRouter} from "react-router-dom";
import {Provider} from "react-redux";
import store from "./store";
import {persist} from "./store";
import {PersistGate} from "redux-persist/integration/react";
import {persistStore} from "redux-persist";

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <Provider store={store}>
    <PersistGate loding={null} persistor={persist}>
      <BrowserRouter>
        <App/>
      </BrowserRouter>
    </PersistGate>
  </Provider>
);

reportWebVitals()

 

장단점

  • 장점
    • 랜더링 여부를 선택할 수 있다. (부분 랜더링 가능)
    • 애플리케이션이 커지고 복잡해져도 문제없다.
    • 관리하는 데이터가 복잡해도 문제없다.
    • saga, thunk 같은 미들웨어를 추가적으로 사용할 수 있다.
    • 비동기적인 처리나 사이드 이펙트를 관리하기에 좋다.
  • 단점
    • dependency가 필요하다.
    • 초반 세팅에 시간이 걸린다.
    • 코드가 많이 분산되어서 찾기가 불편할 수 있다.