728x90
728x90

로컬 스토리지(LocalStorage)에 내용을 저장하고, 전역 상태 관리 라이브러리(Redux)와 동기화 하는 방법

들어가며

  • 리액트(React.js)에서 특정 변수를 로컬 스토리지(Local Storage)에 저장하고, 전역 상태 관리 라이브러리(Redux)와 동기화 시키는 방법을 정리해본다.
    • 이렇게 함으로써, 사용자의 입력을 받아 특정 변수를 화면에 표시해줘야 할 경우 새로고침을 해도 동일한 내용이 표시되게 할 수 있다.

 

로컬 스토리지(Local Storage)

개념

  • 브라우저에 데이터를 영구적으로 저장할 수 있는 방법
  • 브라우저가 닫혀도 데이터가 유지되며, 도메인별로 구분되어 저장된다.
  • 로컬 스토리지는 키-값(Key-Value) 형식으로 데이터를 저장하며, 데이터는 문자열 형식으로만 저장할 수 있다.
    • 따라서 객체(Object)배열(Array) 같은 복잡한 데이터는 JSON으로 변환하여 저장하고, 가져올 때 다시 파싱(Parsing)해야 한다.
      • JSON으로 변환하기 위해서는 JSON.stringfy(객체|배열) 메서드를 사용하고, JSON을 다시 객체/배열로 파싱하려면 JSON.parse(JSON변수)를 사용한다.
  • 저장된 데이터는 사용자가 명시적으로 삭제하거나, 브라우저의 캐시를 지우기 전까지 유지된다.
  • 최대 저장 용량은 보통 5MB 정도이다.
  • 문자열 형태로만 데이터를 저장한다. (객체 저장 시 JSON으로 변환)

 

사용 예제 : JSON 변환 & 파싱(Parsing)

객체
const user = {
name: 'Peter',
age: 2024,
isMember: true
};
// 객체 -> 문자열 형태로 변환
const userJson = JSON.stringfy(user);
// 로컬 스토리지에 저장
localStorage.setItem('user', userJson);
// 파싱
const storedUser = JSON.parse(localStorage.getItem('user'));

 

배열
const favoriteColors = ['red', 'blue', 'green'];
// 객체 -> 문자열 형태로 변환
const favoriteColorsJson = JSON.stringfy(favoriteColors);
// 로컬 스토리지에 저장
localStorage.setItem('colors', favoriteColorsJson);
// 파싱
const storedColors = JSON.parse(localStorage.getItem('colors'));

 

객체 + 배열이 혼합된 형태
const settings = {
theme: 'dark',
shortcuts: ['Ctrl+S', 'Ctrl+C', 'Ctrl+V'],
layout: {
header: true,
sidebar: false
}
};
// 객체+배열 -> 문자열 형태로 변환
const settingsJson = JSON.stringfy(settings);
// 로컬 스토리지에 저장
localStorage.setItem('settings', settingsJson);
// 파싱
const storedSettings = JSON.parse(localStorage.getItem('settings'));

 

주요 메서드

  • setItem(key, value) : 로컬 스토리지에 데이터 저장하기
  • getItem(key) : 로컬 스토리지에서 데이터 가져오기
  • removeItem(key) : 특정 데이터를 삭제하기
  • clear() : 로컬 스토리지의 모든 데이터를 삭제하기
  • length : 로컬 스토리지에 저장된 데이터의 개수 반환

 

사용 예제 : 주요 메서드

데이터 저장
localStorage.setItem('username', 'peter');
const user = { name: 'peter', age: 2024 };
// 로컬 스토리지에 데이터 저장하기
localStorage.setItem('user', JSON.stringify(user));

 

데이터 가져오기
// 로컬 스토리지에서 데이터 가져오기
const username = localStorage.getItem('username');
console.log(username); // peter
const storedUser = JSON.parse(localStorage.getItem('user'));
console.log(storedUser); // { name: 'peter', age: 2024 }

 

데이터 삭제하기
// 특정 데이터 삭제하기
localStorage.removeItem('username');
// 전체 데이터 삭제하기
localStorage.clear();

 

(참고) 쿠키(Cookie) vs. 로컬 스토리지(Local Storage) vs. 세션(Session)

  로컬 스토리지(Local Storage) 쿠키(Cookie) 세션(Session)
 저장 위치 클라이언트 클라이언트 서버
저장 용량 5~10MB 4KB 서버 설정에 따라 다르다.
유효 기간 영구적
(사용자가 명시적으로 삭제하지 않는 한 유지)
설정 가능
(세션 쿠키는 브라우저 종료 시 삭제)
브라우저 종료 시 삭제
(서버에서 설정 가능)
데이터 전송 서버로 전송되지 않음. 서버로 자동 전송 서버에서 관리,
클라이언트에는 세션 ID만 저장
보안 클라이언트 자바스크립트로 접근 가능, 보안 취약 HttpOnly, Secure 옵션으로 보호 가능 서버에서 관리, 비교적 안전
사용 목적 클라이언트 측 영구 데이터 저장 세션 관리, 인증 정보 유지, 상태 저장 사용자 인증 정보 등 일시적 상태 저장

 

리덕스(Redux)와 로컬 스토리지의 값 동기화 하기

  • 전역 상태 관리 라이브러리인 리덕스(Redux)와 로컬 스토리지의 값을 동기화하여 페이지가 새로고침 되더라도 값이 유지되도록 해보자.
  • 여러개의 객체를 담고 있는 배열을 로컬 스토리지에 저장하는 경우를 생각해본다.
    • 예: [{id: *, text: *, translatedText: *}, ..., {id: *, text: *, translatedText: *}]
const data = {
id: Date.now(),
text,
translatedText,
};

 

필요한 패키지 설치

  • 우선, 필요한 패키지들을 설치해준다.
$ npm install redux-persist # 상태를 영구적으로 저장할 수 있게 해주는 도구
$ npm install @reduxjs/toolkit # 리덕스를 더 간편하고 효율적으로 사용하기 위해 만들어진 도구

 

/store/textSlice.js
  • 여러 객체를 담고 있는 배열(Array)를 로컬 스토리지에 저장할 것이기 때문에 initialStatetextArrays 값을 배열([]) 형태로 지정해준다.
import { createSlice } from '@reduxjs/toolkit';
const initialState = {
textArrays: [],
};
const textSlice = createSlice({
name: 'text',
initialState,
reducers: {
// 상태를 업데이트 하는 리듀서 함수
saveText: (state, action) => {
state.textArrays.push(action.payload);
},
},
});
export const { saveText } = textSlice.actions;
export default textSlice.reducer;

 

/store/store.js
  • store 변수 정의 시, middleware 부분은  리덕스 툴킷에서 미들웨어를 설정할 때, redux-persist와 관련된 액션들이 직렬화 검사에서 무시되도록 하는 설정이다.
    • 이 부분을 설정하지 않으면 개발자 도구에서 경고 메시지가 출력된다.
    • 리덕스 툴킷과 redux-persist의 직렬화 방식에 차이가 있어서 발생하는 오류이다.
      • 리덕스(Redux)에서는 상태(state)나 액션(action)이 직렬화 가능한(serializable) 데이터여야 한다는 제약이 있다.
        • 직렬화 가능한 데이터란, JSON으로 변환 가능한 데이터(객체, 배열, 문자열, 숫자 등)를 의미 한다.
        • 리덕스에서 직렬화되지 않은 값(함수, DOM 요소 등)을 사용하면 예기치 않은 동작이 발생할 수 있기 때문에, 리덕스 툴킷은 기본적으로 직렬화 검사를 활성화한다.
      • 그러나 redux-persist에서 사용하는 액션(persist/PERSIST, persist/REHYDRATE)은 직렬화되지 않은 데이터를 포함할 수 있으므로, 이 액션들이 직렬화 검사에서 제외되도록 설정해야 한다.
        • 그렇지 않으면 경고나 오류가 발생할 수 있다.
import { combineReducers } from 'redux';
import { persistReducer, persistStore } from 'redux-persist';
import { configureStore } from '@reduxjs/toolkit';
import storage from 'redux-persist/lib/storage'; // 기본적으로 로컬 스토리지 사용하기
import textReducer from './textSlice';
// redux-persist 설정
const persistConfig = {
key: 'root', // 로컬 스토리지에 저장할 데이터의 이름 설정
storage, // 저장소로 로컬 스토리지 사용하기
};
// 여러 리듀서를 결합한 하나의 리듀서 객체
const rootReducer = combineReducers({
text: textReducer,
});
// 퍼시스트 리듀서 생성 (기존의 rootReducer에 persistConfig를 적용한다.)
const persistedReducer = persistReducer(persistConfig, rootReducer);
export const store = configureStore({
reducer: persistedReducer,
// 리덕스에서 미들웨어를 설정할 때, redux-persist 관련된 액션을 무시하도록 설정
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({
serializableCheck: {
ignoredActions: ['persist/PERSIST', 'persist/REHYDRATE'],
},
}),
});
// 리덕스 스토어에 redux-persist를 적용하여 저장소와 리덕스 스토어 간의 동기화를 관리하는 객체 생성
// persistor는 저장된 상태를 복원하고, 리덕스 상태가 변할 때마다 자동으로 저장소에 상태를 동기화한다.
export const persistor = persistStore(store);

 

  • 비직렬화 관련 오류가 발생할 경우, 다음과 같이 간단하게 getDefaultMiddlewareserializableCheckfalse로 설정해준다.
// 스토어 설정
export const store = configureStore({
reducer: {
global: persistedReducer,
},
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({
serializableCheck: false, // 비직렬화 값 무시
}),
});

 

/App.jsx
  • 리덕스의 Provider로 내부의 컴포넌트들을 감싸준다.
import { Provider } from 'react-redux';
import { store } from './store/store';
export const App = () => {
return (
<Provider store={store}>
...
</Provider>
);
};
export default App;

 

/src/Test.jsx
  • saveText(data) 액션을 리덕스 스토어에 디스패치하여 상태를 변경시킨다.
  • 그리고 해당 값을 로컬 스토리지에 저장시켜준다.
import { useDispatch } from 'react-redux';
import { saveText } from '../store/textSlice';
export const App = () => {
const dispatch = useDispatch();
// ...
if (text && translatedText) {
const data = {
id: Date.now(),
text,
translatedText,
};
// Redux에 저장
dispatch(saveText(data));
// LocalStorage에 저장
localStorage.setItem('savedTextPair', JSON.stringify(data));
}
}

 

참고 사이트

 

HTTP 쿠키 - HTTP | MDN

HTTP 쿠키(웹 쿠키, 브라우저 쿠키)는 서버가 사용자의 웹 브라우저에 전송하는 작은 데이터 조각입니다. 브라우저는 그 데이터 조각들을 저장해 놓았다가, 동일한 서버에 재 요청 시 저장된 데이

developer.mozilla.org

 

Window.localStorage - Web API | MDN

localStorage 읽기 전용 속성을 사용하면 Document 출처의 Storage 객체에 접근할 수 있습니다. 저장한 데이터는 브라우저 세션 간에 공유됩니다. localStorage는 sessionStorage와 비슷하지만, localStorage의 데이

developer.mozilla.org

 

전형적인 HTTP 세션 - HTTP | MDN

HTTP와 같은 클라이언트-서버 프로토콜에서, 세션은 다음의 세 가지 과정으로 이루어집니다.

developer.mozilla.org

 

redux-persist

persist and rehydrate redux stores. Latest version: 6.0.0, last published: 5 years ago. Start using redux-persist in your project by running n±iredux-persist. There are 1425 other projects in the npm registry using redux-persist.

www.npmjs.com

 

Persist state with Redux Persist using Redux Toolkit in React - LogRocket Blog

With Redux Persist, developers can save the Redux store in persistent storage so even after refreshing the browser, the site state will be preserved.

blog.logrocket.com

 

728x90
728x90

로컬 스토리지(LocalStorage)에 내용을 저장하고, 전역 상태 관리 라이브러리(Redux)와 동기화 하는 방법들어가며로컬 스토리지(Local Storage)개념사용 예제 : JSON 변환 & 파싱(Parsing)주요 메서드사용 예제 : 주요 메서드(참고) 쿠키(Cookie) vs. 로컬 스토리지(Local Storage) vs. 세션(Session)리덕스(Redux)와 로컬 스토리지의 값 동기화 하기필요한 패키지 설치참고 사이트