Programming/JavaScript

[JavaScript] 리액트에 indexedDB 사용하기

kkt9102 2024. 8. 18. 12:37
728x90

일전에 사이드프로젝트를 진행하면서 로컬스토리지와 세션스토리지 그리고 쿠키를 이용했었고

지금도 회사업무를 진행하면서 세션과 로컬스토리지, 쿠키를 이용하고있습니다.

 

하지만.... 사이드프로젝트를 진행할 당시 뭔가... 뭔가가 부족했었는데...

요즘이야 백, 프론트 상관없이 올포지션을 다 다룰수 있어야하지만... 난 아직도 부족하기 때문에

백엔드 프로젝트를 혼자서 구현하기가 아직도 버거워요. 그러다가 문득 찾은 것이 indexedDB!!!

 

이름 그대로 DB이다! mdn web docs 에서는 이렇게 설명하고 있습니다.

 

IndexedDB는 파일이나 블롭 등 많은 양의 구조화된 데이터를 클라이언트에 저장하기 위한 로우 레벨 API입니다. IndexedDB API는 인덱스를 사용해 데이터를 고성능으로 탐색할 수 있습니다.

 

라고 설명하고 있습니다! 조금 더 자세한 설명은 아래의 링크로 접속하시면 볼 수 있습니다!

 

https://developer.mozilla.org/ko/docs/Web/API/IndexedDB_API

 

IndexedDB API - Web API | MDN

IndexedDB는 파일이나 블롭 등 많은 양의 구조화된 데이터를 클라이언트에 저장하기 위한 로우 레벨 API입니다. IndexedDB API는 인덱스를 사용해 데이터를 고성능으로 탐색할 수 있습니다. Web Storage는

developer.mozilla.org

 

1. React에 indexedDB 살짝 끼얹어보기

이제 진짜로 indexedDB를 React 프로젝트에 적용시켜보겠습니다.

일단 프로젝트의 root 파일에 indexedDB를 열어준다고(?) 작성을 해줍니다.

 

MDN 문서에서는 아래와 같이 나와있습니다.

// In the following line, you should include the prefixes of implementations you want to test.
window.indexedDB =
  window.indexedDB ||
  window.mozIndexedDB ||
  window.webkitIndexedDB ||
  window.msIndexedDB;
// DON'T use "var indexedDB = ..." if you're not in a function.
// Moreover, you may need references to some window.IDB* objects:
window.IDBTransaction =
  window.IDBTransaction ||
  window.webkitIDBTransaction ||
  window.msIDBTransaction;
window.IDBKeyRange =
  window.IDBKeyRange || window.webkitIDBKeyRange || window.msIDBKeyRange;
// (Mozilla has never prefixed these objects, so we don't need window.mozIDB*)

다만 TypeScript를 사용하면 window.indexedDB 만 인식되고 있었습니다.

 

저는 작성할 때 root 파일에 indexedDB를 초기화 하고 필요한 객체 저장소를 생성하는 함수를 실행시키게 설정해놨습니다.

 

export const indexedDBStart = () => {
  const indexedDB = window.indexedDB;
  const dbName = "tableName";
  const request = indexedDB.open(dbName, 1);
  request.onupgradeneeded = (e: any) => {
    const db = e.target.result;
    const articleStore = db.createObjectStore("article", {
      keyPath: "id",
      autoIncrement: true,
    });
    const memberStore = db.createObjectStore("member", {
      keyPath: "id",
      autoIncrement: true,
    });
  };
  request.onsuccess = (e: any) => {
  	console.log("성공");
  };
  request.onerror = (e: any) => {
    console.error("실패 : ", e.target.error);
  };
};

 

indexedDBStart 가 실행되면 dbName 이라는 이름의 DB, 그리고 버전은 1인 indexedDB 를 열어달라고 요청합니다. 그리고 만약 해당 indexedDB가 없으면 dbName, 버전 1 이라는 indexedDB를 생성하게 됩니다.

 

request.onupgradeneeded 를 통해 데이터베이스 객체를 가져온 후 article 과 member 란 객체 저장소를 생성하게 됩니다.

 

그리고 객체 저장소 생성에 성공하면 console.log에 '성공' 이라는 메시지가 출력되고

만약 실패한다면 '실패 : error' 가 출력됩니다.

 

자 이제 개발자모드를 켜서 확인해보시면 아래와 같이 브라우저 저장소가 생성되어있습니다!

2. indexedDB에 데이터 저장해보기

이제 저장소를 만들었으니 해당 저장소에 post 하는 방법을 알아보겠습니다.

먼저 article 에 게시글을 저장해보겠습니다.

 

export const indexedDBPost = (postDatas: any) => {
  const idb = window.indexedDB;
  return new Promise((resolve, reject) => {
    const dbOpen = idb.open("tableName", 1);
    dbOpen.onsuccess = () => {
      const db = dbOpen.result;
      const transaction = db.transaction("article", "readwrite");
      const tableNameDB = transaction.objectStore("article");

      const postData = tableNameDB.put({
        title: postDatas.title,
        contents: postDatas.contents,
        createDt: postDatas.createDt,
        writer: postDatas.writer,
      });

      postData.onsuccess = (e) => {
        transaction.oncomplete = () => {
          db.close();
        };
        resolve(e.type);
      };

      postData.onerror = (e) => {
        console.error("error : ", e);
        reject(e);
      };

      transaction.oncomplete = () => {
        db.close();
      };
    };
  });
};

해당 함수를 통해 글 작성 버튼을 누르면 아래의 캡처화면과 같이 indexedDB에 게시글 정보가 저장됩니다.

 

해당 캡쳐에서는 샘플용으로 간단하게 작성해서 데이터를 작성했지만 실제로는 쿠키나  스토리지보다 더 많은 데이터를 저장시킬 수 있습니다.

 

해당 캡쳐는 제가 사이드프로젝트를 하면서 indexedDB를 활용하여 작성 한 데이터 샘플입니다. 캡쳐본처럼 다양한 데이터를 저장시킬 수 있는 장점이 있습니다.

 

3. indexedDB에 저장된 데이터 불러오기

그럼 간단하게 데이터를 저장해봤는데 이번에는 저장된 데이터를 불러오는 방법을 알아보겠습니다!

 

export const getAllDataFromIndexedDB = () => {
  const idb = window.indexedDB;
  return new Promise((resolve, reject) => {
    const dbOpen = idb.open("tableName", 1);

    dbOpen.onsuccess = () => {
      let db = dbOpen.result;
      const transaction = db.transaction("article", "readonly");
      const reviewDB = transaction.objectStore("article");
      const review = reviewDB.getAll();

      review.onsuccess = (e: any) => {
        const data = e.srcElement.result;
        console.log('성공 데이터 불러오기',data);
        resolve(data);
      };

      review.onerror = (e) => {
        console.log("error", e);
        reject(e);
      };

      transaction.oncomplete = () => {
        db.close();
      };
    };
  });
};

 

indexedDB에 저장된 데이터를 불러오는 코드입니다. 기본적은 구조는 post와 비슷합니다.

먼저 오픈 할 테이블을 선택해준 후 dbOpen 이 성공하면 해당 db안의 컬럼을 선택해주고 컬럼안의 데이터들을 불러와주면 끝입니다.

 

정상적으로 console에 찍히는 모습을 볼 수 있습니다.

 

만약 저장된 데이터가 여러개라면 아래의 캡쳐와 같이 console에 찍히게 됩니다!

 

이제 컴포넌트에서 불러온 데이터를 state애 저장 후 사용하면 됩니다!

 

만약 특정한 값의 데이터만 불러오고 싶은 경우가 있는데 저는 filter를 통해 특정 데이터를 선택한 후 resolve에 넣어주어 사용하고 있습니다.

 

// 특정 데이터 선별해서 사용하기

export const getAllDataFromIndexedDB = (postWriter:string) => {
  const idb = window.indexedDB;
  return new Promise((resolve, reject) => {
    const dbOpen = idb.open("tableName", 1);

    dbOpen.onsuccess = () => {
      let db = dbOpen.result;
      const transaction = db.transaction("article", "readonly");
      const reviewDB = transaction.objectStore("article");
      const review = reviewDB.getAll();

      review.onsuccess = (e: any) => {
        const data = e.srcElement.result;
        const filterData  = data.filter((item) => item.writer === postWriter)
        console.log('필터 불러오기',filterData);
        resolve(filterData);
      };

      review.onerror = (e) => {
        console.log("error", e);
        reject(e);
      };

      transaction.oncomplete = () => {
        db.close();
      };
    };
  });
};

 

 

4. indexedDB에 저장된 데이터 삭제하기

삭제또한 매우 간단합니다. indexedDB에 저장 시 자동으로 생성되는 id값으로 데이터 삭제를 진행합니다.

 

export const indexedDBDelete = (id: number) => {
  const idb = window.indexedDB;
  return new Promise((resolve, reject) => {
    const dbOpen = idb.open("tableName", 1);
    dbOpen.onsuccess = () => {
      const db = dbOpen.result;
      const transaction = db.transaction("article", "readwrite");
      const tableNameDB = transaction.objectStore("article");

      const deleteRequest = tableNameDB.delete(id);

      deleteRequest.onsuccess = () => {
        transaction.oncomplete = () => {
          db.close();
          resolve(true);
        };
      };

      deleteRequest.onerror = (e) => {
        console.error("error : ", e);
        reject(e);
      };

      transaction.oncomplete = () => {
        db.close();
      };
    };
  });
};

삭제 함수를 통해 삭제를 진행하는데 만약 id =2 인 값을 삭제하면 아래와 같이 해당 id를 가진 컬럼이 삭제됩니다.

 

 

이상 간단하게 indexedDB사용법을 정리해봤습니다.

indexedDB를 메인으로 사용하기에는 다방면으로 무리가 있을 듯 하지만 그래도 로컬환경에나서 프론트 기준에서 백엔드 작업이 진행되지 않았을 때에는 필요한 데이터를 최대한 비슷한 환경에서 테스트해보기에는 좋을 것 같습니다.

 

잘못된 부분 지적은 언제나 감사합니다.