프론트엔드로 가는 길/portfolio 제작 여정기 👩🏻‍💻

07. 자살예방웹사이트 - redux-persist 로그인 유지

woody-j 2023. 9. 12. 18:59

나는 처음..토큰을 리덕스에 저장했다.

그래서 새로고침 시 로그아웃이 됐다..새로고침 시 로그아웃...로그아웃.. 계속 로그아웃

 

왜?

 

리덕스의 상태가 메모리 내에서만 유지되기 때문이었다.

리덕스 상태는 브라우저의 메모리에 저장되고, 새로고침하거나 페이지를 닫고 다시 열면 리덕스 상태가 초기화된다.

그래서

-> 브라우저 저장소를 사용

-> 쿠키 사용

-> 페이지 로드시 토큰 재요청

방식이 있었는데 나는 브라우저 저장소 사용으로 redux-persist를 선택했다.

 

Redux-Tookit 개념 정리

 

[userLoginAccessTokenSlice.tsx]

import { createSlice, PayloadAction } from "@reduxjs/toolkit";

const initialState = "";

export const userLoginAccessTokenSlice = createSlice({
  name: "userLoginAccessToken",
  initialState,
  reducers: {
    setUserLoginAccessTokenSlice: (state, action: PayloadAction<any>) => {
      return action.payload;
    },
  },
});

export const { setUserLoginAccessTokenSlice } = userLoginAccessTokenSlice.actions;

[userLoginDataSlice.tsx]

import { createSlice, PayloadAction } from "@reduxjs/toolkit";
import { PURGE } from "redux-persist";

// 피자집 정보 양식
interface UserLoginDataState {
  uid: string;
  userEmail: string;
  nickName: string;
  authToken: any;
}

// 피자집이 문을 열 때 처음에 가지는 상태, 아무도 주문 안함
const initialState: UserLoginDataState = {
  uid: "",
  userEmail: "",
  nickName: "",
  authToken: "",
};

// 주문 정보를 처리하는 곳
// 고객이 주문하면 주문 정보를 받아와서 상태를 업데이트
export const userLoginDataSlice = createSlice({
  name: "userLoginData",
  initialState,
  reducers: {
  // 주문을 받아서 상태를 업데이트하는 함수 : 주문한 내용을 받으면, 그 정보를 피자집 상태에 추가
    setUserLoginDataSlice: (state, action: PayloadAction<UserLoginDataState>) => {
     // 피자 상태의 현재 상태를 가져와서 새로운 주문 내역을 가져와서 기존 상태와 병합
     return { ...state, ...action.payload };
    },
  },
  // 주문 정보를 초기화하는 역할
  extraReducers: (builder) => {
    builder.addCase(PURGE, () => initialState);
  },
});

export const { setUserLoginDataSlice } = userLoginDataSlice.actions;

 

createSlice

자! 피자가게를 갔다.

피자 레스토랑의 createSlice는 주문하기 쉽게 만들어진 메뉴판이다.

메뉴판은 이미 정의된 여러 가지 피자와 추가 옵션을 포함한다.

 

메뉴판에서 피자를 주문하면 주방에서 피자를 만들고,

다음으로는 피자를 제공하거나 배달할 수 있습니다.

이 주방에서의 피자 만들기 및 제공하기 과정은 Redux 리듀서와 상당히 유사하다.

 

1) 주문 메뉴판을 만들어 주문 과정을 간단하게 한다!

메뉴판에는 다양한 피자와 토핑 옵션에 대한 정보가 있으며, 주문하는 고객은 그냥 원하는 피자와 토핑을 선택하면 된다.

 

2) Redux에서 상태(state)와 액션(action)을 다루기 위한 간단한 도구다.

이 도구를 사용하면 상태 관리 코드를 더 쉽게 작성할 수 있다.

 

상태(State):

상태는 현재 피자 레스토랑의 상황

예를 들어, 주방에는 어떤 주문이 있는지, 각 주문이 어느 단계에 있는지, 피자 레스토랑의 재고가 어떻게 되는지 등의 정보를 포함한다. Redux에서 상태애플리케이션 전반적인 데이터를 관리하는 곳이며,

예를 들어 사용자 로그인 상태, 애플리케이션 설정, 데이터 리스트 등이 상태로 관리된다.

 

액션(Action):

액션은 피자 레스토랑에서 일어나는 일들 -> 주문을 받는 것, 주방에서 피자를 만드는 것, 서빙하는 것 등 모든 작업은 액션으로 표현

Redux에서 액션상태에 변화를 일으키는 이벤트나 작업을 나타냅니다.

사용자가 로그인하는 것, 데이터를 불러오는 것, 설정을 변경하는 것 등 Redux 상태에 영향을 주는 모든 것이 액션입니다.

 

configureStore

자! 피자 가게를 효율적으로 운영하려면 어떻게 해야하나!

도구를 잘 사용해야쥐! 피자 가게를 운영하기 위한 전반적인 설정과 도구라고 생각할 수 있다.

Reducers: Redux 스토어에 사용될 리듀서 (데이터 처리 함수)

 주방에서 어떤 종류의 피자를 만들어야 하는지, 주문을 받을 때 어떻게 처리해야 하는지에 대한 지침을 담은 레시피와 같습니다. 

이 레시피에 따라 주문이나 상태 변경을 처리합니다.

Middleware: Redux 미들웨어를 설정하고 사용할 수 있게 해주는 배열

주방 스태프에 추가 지침을 제공하는 도우미로 생각할 수 있습니다. 

예를 들어, 주방에서 피자를 만들 때, 어떤 추가 재료를 더해야 하는 경우 미들웨어가 주방 스태프에게 지시할 수 있습니다.

DevTools: 개발 도구를 활성화할지 여부를 나타내는 불리언 값

주방의 상황을 모니터링하고 기록하는 도구로 생각할 수 있습니다. 

주문 내역, 피자 재고, 주방 작업 기록 등을 추적하여 문제를 해결하거나 레스토랑을 개선하는 데 도움이 됩니다.

Redux-persist 개념 정리

import { configureStore } from "@reduxjs/toolkit";
import thunk from "redux-thunk";
import { combineReducers } from "redux";
import { userLoginAccessTokenSlice } from "./reducer/userData/userData/userLoginAccessTokenSlice";
import { userLoginDataSlice } from "./reducer/userData/userData/userLoginDataSlice";
import { persistReducer } from "redux-persist";
import storage from "redux-persist/es/storage";

const reducers = combineReducers({
  userLoginDataSlice: userLoginDataSlice.reducer,
  userLoginAccessTokenSlice: userLoginAccessTokenSlice.reducer,
});

const persistConfig = {
  key: "root",
  storage, // localStorage에 저장
};

const persistedReducer = persistReducer(persistConfig, reducers);

export const store = configureStore({
  reducer: persistedReducer,
  devTools: process.env.NODE_ENV !== "production",
  middleware: [thunk],
});

Storerage

새로고침해도 state 값이 사라지지 않도록, localstorage에 reducer를 저장한다.

localStorage 저장 -> import storage from 'redux-persist/lib/storage
session Storage 저장 ->import storageSession from 'redux-persist/lib/storage/session

persistConfig = { } 

데이터 저장 방법과 위치를 설정한 구성 객체.

(피자 상자)

피자 상자에는 피자를 오래 보관하기 위한 설정

이 설정들은 어떤 종류의 피자를 저장하고, 어떻게 저장할지를 결정

const persistConfig = {
  key: "root",// 저장된 데이터를 식별하는데 사용되는 이름
  storage, // 실제로 데이터를 저장하는 장소
};


persistReducer

데이터 저장 및 복원을 관리, persistConfig에 따라 데이터를 다룸

(피자 저장소 직원)

피자 상자(persistConfig)를 받아서 그 안에 어떻게 피자를 저장할지를 처리

 

const persistedReducer = persistReducer(persistConfig, reducers);
// 데이터를 저장하고 관리

persistStore()

 저장된 데이터를 관리하고, 필요할 때 불러오는 스토리지 역할

(피자 저장소)

이 저장소는 실제로 피자를 저장하고, 필요할 때 피자를 꺼내와서 제공

persistStore()는 마치 피자집의 저장고나 창고와 같다.

주문한 피자를 저장하고, 나중에 고객에게 제공할 준비를 한다.


PersistGate

초기화를 기다렸다가 앱을 렌더링하는 보호 장치

(피자 상점 문)

이 문은 피자 상점이 열리기 전까지 기다릴 때 사용한다.

피자 상점 문은 여는데 시간이 걸릴 수 있으므로, 문이 열릴 때까지 고객은 기다려야 한다.

이렇게 PersistGate는 저장된 피자를 모두 로드할 때까지 앱이 화면에 나타나지 않도록 한다.

export const store = configureStore({
// 스토어가 액션을 처리할 때 상태를 persistedReducer로 전달하고, 이 리듀서에서 데이터를 저장하거나 관리
  reducer: persistedReducer,
  devTools: process.env.NODE_ENV !== "production",
  //thunk는 비동기 작업을 처리하고, 액션을 디스패치할 때 함수를 사용
  middleware: [thunk],
});


PURGE

저장된 데이터를 완전히 삭제하고 초기 상태로 되돌리는 명령어

 

(피자 재료 폐기)

피자 상점이나 피자 가게가 피자 재료를 버리는 것과 비슷하다.

피자 상태를 초기화하고, 모든 저장된 피자를 폐기하는 역할을 한다. 

 

 

참고 블로그 :

https://velog.io/@dy6578ekdbs/Redux-persist-%EB%A1%9C%EA%B7%B8%EC%9D%B8-%EA%B5%AC%ED%98%84