본문 바로가기

Programming/JavaScript

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

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

 

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