[React] LocalStorage 데이터 저장하기

이재훈·2023년 6월 16일
1

React

목록 보기
25/27

데이터를 DB에 저장하여 가져올 수 있지만 프론트만 구현중이기 때문에 localStorage를 사용하여 데이터를 저장해보도록 하겠습니다.

localStorage는 Web Storage의 한 종류입니다. 먼저 Web Storage API를 알아보도록 하겠습니다.

Web Storage API

브라우저에서 키/값 쌍을 쿠키보다 훨씬 직관적으로 저장할 수 있는 방법을 제공합니다.

Web Storage 종류

sessionStorage

  1. 각각의 출처에 대해 독립적인 저장 공간 페이지 세션이 유지되는 동안(브라우저가 열려있는 동안) 제공합니다.
    동일출처 예시
http://example.com/app1/index.html 
http://example.com/app2/index.html

다른출처 예시

http://example.com 
http://www.example.com 
http://myapp.example.com
  1. 세션에 한정해, 즉 브라우저 또는 탭이 닫힐 때까지만 데이터를 저장합니다.
  2. 데이터를 절대 서버로 전송하지 않습니다.
  3. 저장 공간이 쿠키보다 큽니다.(최대 5MB)

localStorage

  1. sessionStorage와 같지만 브라우저를 닫았다 열어도 데이터가 남아있습니다.
  2. 유효기간 없이 데이터를 저장하고, js를 사용하거나 브라우저 캐시 or 로컬 저장 데이터를 지워야만 사라집니다.
  3. 저장 공간이 cookie, sessionStorage보다 큽니다.

출처 : mdn web docs
https://developer.mozilla.org/ko/docs/Web/API/WebStorage_API#web_storage%EA%B0%9C%EB%85%90%EA%B3%BC_%EC%82%AC%EC%9A%A9%EB%B2%95

저는 웹 브라우저가 꺼져도 데이터가 날라가는 것을 원하지 않기 때문에 localStorage를 사용하도록 하겠습니다.

App 컴포넌트에 아래 코드를 작성해줍니다.

useEffect(() => {
  localStorage.setItem("key", 10);
}, []);

App 컴포넌트가 처음 렌더링 될 때 이 함수가 실행됩니다.

개발자 도구 > application 탭에서 데이터가 저장이 되었는지 확인해줍니다.

여러가지 자료형을 넣어보도록 하겠습니다.

useEffect(() => {
  localStorage.setItem("item1", 10);
  localStorage.setItem("item2", "10");
  localStorage.setItem("item3", { value: 30 });
}, []);


객체는 스토리지가 받아들일 수 없는 값이기 때문에 Object object로 나타나 집니다. 그래서 직렬화를 사용하여 저장을 합니다.

localStorage.setItem("item3", JSON.stringify({ value: 30 }));

로컬 스토리지에서 값을 꺼내보도록 하겠습니다.

function App() {
  useEffect(() => {
    const item1 = localStorage.getItem("item1");
    const item2 = localStorage.getItem("item2");
    const item3 = localStorage.getItem("item3");
    console.log({ item1, item2, item3 });
  }, []);

item1을 저장할 때 number type으로 저장했지만 꺼내보니 문자열 입니다. 기본적으로 localStrage에 저장될 때는 문자열로 저장이 됩니다. 객체 또한 문자열로 꺼내졌습니다. parseInt와 JSON.pare를 사용하여 형 변환을 직접 해줘야 합니다.

function App() {
  useEffect(() => {
    const item1 = parseInt(localStorage.getItem("item1"));
    const item2 = localStorage.getItem("item2");
    const item3 = JSON.parse(localStorage.getItem("item3"));
    console.log({ item1, item2, item3 });
  }, []);

이제 실제 데이터를 localStrage에 담아보도록 하겠습니다.

App.js

import React, { useEffect, useReducer, useRef } from "react";
import "./App.css";
import { BrowserRouter, Route, Routes } from "react-router-dom";
import Home from "./pages/Home";
import Edit from "./pages/Edit";
import New from "./pages/New";
import Diary from "./pages/Diary";

const reducer = (state, action) => {
  let newState = [];
  switch (action.type) {
    case "INIT": {
      return action.data;
    }
    case "CREATE": {
      newState = [action.data, ...state];
      break;
    }
    case "REMOVE": {
      newState = state.filter((it) => it.id !== action.targetId);
      break;
    }
    case "EDIT": {
      newState = state.map((it) =>
        it.id === action.data.id ? { ...action.data } : it
      );
      break;
    }
    default:
      return state;
  }
  localStorage.setItem("diary", JSON.stringify(newState));
  return newState;
};

export const DiaryStateContext = React.createContext();
export const DiaryDispatchContext = React.createContext();

function App() {
  const [data, dispatch] = useReducer(reducer, []);

  useEffect(() => {
    const localData = localStorage.getItem("diary");
    if (localData) {
      const diaryList = JSON.parse(localData).sort(
        (a, b) => parseInt(b.id) - parseInt(a.id)
      );
      dataId.current = parseInt(diaryList[0].id) + 1;
      dispatch({ type: "INIT", data: diaryList });
    }
  }, []);

  const dataId = useRef(0);
  // CREATE
  const onCreate = (date, content, emotion) => {
    dispatch({
      type: "CREATE",
      data: {
        id: dataId.current,
        date: new Date(date).getTime(),
        content,
        emotion,
      },
    });
    dataId.current += 1;
  };
  // REMOVE
  const onRemove = (targetId) => {
    dispatch({ type: "REMOVE", targetId });
  };
  // EDIT
  const onEdit = (targetId, date, content, emotion) => {
    dispatch({
      type: "EDIT",
      data: {
        id: targetId,
        date: new Date(date).getTime(),
        content,
        emotion,
      },
    });
  };
  return (
    <DiaryStateContext.Provider value={data}>
      <DiaryDispatchContext.Provider value={{ onCreate, onEdit, onRemove }}>
        <BrowserRouter>
          <div className="App">
            <Routes>
              <Route path="/" element={<Home />}></Route>
              <Route path="/new" element={<New />}></Route>
              <Route path="/edit/:id" element={<Edit />}></Route>
              <Route path="/diary/:id" element={<Diary />}></Route>
            </Routes>
          </div>
        </BrowserRouter>
      </DiaryDispatchContext.Provider>
    </DiaryStateContext.Provider>
  );
}

export default App;

reducer function 안에 마지막 줄에 newState를 localStorage에 저장을 합니다.

localStorage.setItem("diary", JSON.stringify(newState));
return newState;

App 컴포넌트 안에 useEffact를 사용하여 페이지가 렌더링 될 때 localStrage에 저장되어 있는 데이터를 꺼내서 dispatch 함수를 호출합니다.

  useEffect(() => {
    const localData = localStorage.getItem("diary");
    if (localData) {
      const diaryList = JSON.parse(localData).sort(
        (a, b) => parseInt(b.id) - parseInt(a.id)
      );
      dataId.current = parseInt(diaryList[0].id) + 1;
      dispatch({ type: "INIT", data: diaryList });
    }
  }, []);


잘 적용된 것을 확인할 수 있습니다.


리액트 공식 홈페이지
https://ko.legacy.reactjs.org/docs/react-api.html#reactmemo
해당 게시글은 인프런 강의
"한입 크기로 잘라 먹는 리액트(React.js) : 기초부터 실전까지(이정환)"
를 정리한 내용입니다. 쉽게 잘 설명해주시니 여러분도 강의를 듣는 것을 추천드립니다.

profile
부족함을 인정하고 노력하자

0개의 댓글