728x90
반응형

개념

react 어플리케이션을 만들때면 전역 상태 관리를 위해 redux를 사용해야 할 때가 있습니다

 

이 전역상태 역시 메모리 상의 상태이기 때문에, 페이지를 새로고침 하거나 앱 프로세스가 초기화되면 전부 초기화 됩니다.

이렇게 되면 로그인이 풀려버리는 등의 상황을 마주할 수 있어요

그렇지 않기 위해서

웹에서는 localStorage, sessionStorage, cookie등 브라우저 스토리지에 이를 저장해두고 동기화를 하여 사용하거나

react-native에서는 fileSystem 혹은 asyncStorage에 저장을 해두어 새로고침이나 앱 종료 후에도 상태를 유지할 수 있습니다.

 

이 과정을 도와주는 라이브러리가 redux-persist 입니다

redux-persist에서는  stoarge engines을 변경함으로써 다양한 환경에서 redux의 값을 저장해줄 수 있습니다

가령 아래와 같은 방식입니다.

// 예시를 위해 몸을 심하게 비튼 코드

const getStorage = () => {
  switch(환경) {
  	case 일렉트론
    	return createElectronStorage()
    case 웹 로컬 스토리지
        return localStorage // import storage from 'redux-persist/lib/storage'
    case 웹 세션 스토리지 
    	return sessionStorage // import storage from 'redux-persist/lib/storage/session'
    case 리액트 네이티브
    	return asyncStorage // import storage from '@react-native-community/async-storage';
    등등
  }
}


const persistConfig = {
	key: 'root',
    storage: getStorage() // 이곳의 storage만 바꿔준다면 다양한 환경에서 사용가능
};

const persistedReducer = persistReducer(persistConfig, rootReducer)

 

이렇게 사용을 할 때 주의해야 하는 점이 있습니다

스토리지에 저장된 값의 구조(타입)과 현재 코드에서 사용되는 형태가 달라지게 된다면 어떻게 될까요?

상황에 따라 브라우저에서는 런타임에러가 발생할 수 있고 

앱에서는 앱의 크래시가 발생할 수 있습니다

 

이러한 상황을 막기 위해 migration을 적절히 해주어야 합니다

이 글에서는 실무에서 migration을 적용하여 기존의 버그들을 피한 상황을 서술하려 합니다

 

실무에서 발생했던 상황은 아래와 같습니다.

redux의 값을 수정했고 코드푸시를 나간이후에 기존 유저의 앱에서 crash가 나는 현상이 발생되었다

 


코드 예시

에러가 나는 상황

기존에 redux-persist를 통해 값이 저장되어 있던 형태

type TodoState = string[] // ['밥먹기', '출근하기']


const todoPersistConfig = {
  key: 'todo',
  storage,
};


const rootReducer = combineReducers({
  todos: persistReducer(todoPersisConfig, todo),
});

 

값을 가져와서 쓰던 형태

const todos = useSelector((state) => state.todos);

return (
  <View>
  	{todos.map((todo) => (
      <Text>{todo}</Text>
    )}
  </View>
)

 

값이 저장되어 있던 형태가 변경되었고 이것이 코드푸시를 통해 배포가 나감

type Todo = { id: number, title: string };

type TodoState = {
  list: Todo[];
}

const todoPersistConfig = {
  key: 'todos',
  storage,
};


const rootReducer = combineReducers({
  todos: persistReducer(todoPersisConfig, todo),
});

 

이때 마이그레이션을 하지 않으면 런타임에서 에러가 발생 

const { list: todos } = useSelector((state) => state.todos);  // <- redux-persist를 통해 storage에
// 저장되어 있던 값은 ['밥먹기', '출근하기']
// list가 존재하지 않음
// 아래 런타임에서 에러 발생

return (
  <View>
  	{todos.map((todo) => (
      <Text>{todo.title}</Text>
    )}
  </View>
)

 

새로운 유저는 영향 x, 기존에 redux에 값이 저장되어 있던 유저만 영향을 받는 상황

=> qa를 어렵게 하고 예측 불가능한 상황이 되어 버림

 위와 같은 이유로 안쓰는 키값을 제거하거나 타입의 변경시 에러 방지를 위해 마이그레이션이 필요합니다

 


마이그레이션 방법

persistConfig를 정의할때 migration이 필요할 경우 migration 코드와 version을 올려주면 됩니다

import { createMigrate } from 'redux-persist'

const migrations = {
  1: (state) => {
  	if (state && typeof state === 'object') {
      return {
        ...state,
        todo: { 
        	list: []
        }
      };
    }
  } 
}


const persistConfig = {
  key: 'root',
  storage,
  version: 1, // 버전을 1로 증가하여 새로운 마이그레이션 트리거
  migrate: createMigrate(migrations, { debug: __DEV__ }),
};

 

 

728x90
반응형

'Frontend > React' 카테고리의 다른 글

pnpm과 이모저모  (0) 2025.11.27
[번역] React Atomic하게 바라보기  (0) 2024.05.19
React patterns 🤔  (0) 2023.06.06
React 공식문서 주요개념 살펴보기  (1) 2022.05.26
React what is JSX? (번역글) 🤔  (2) 2022.04.27

+ Recent posts