FrontEnd/Vue

[Vue-Query] persistQueryClient

Grace 2023. 4. 24. 22:52

https://tanstack.com/query/v4/docs/vue/examples/vue/persister

Vue Query Persister는 나중에 사용할 수 있도록 쿼리 클라이언트를 저장하는 persister와 상호작용하기 위한 유틸리티 집합입니다. 다양한 persister를 사용하여 클라이언트 및 캐시를 다양한 스토리지에 저장할 수 있습니다.

여기서 우리는 indexedDB에 저장했습니다.
indexedDB는 same-origin policy를 따르기 때문에 다른 도메인에서 프로젝트 도메인으로 접근할 수 없습니다.
여기에 HTTP 프로토콜을 적용한 도메인과 로컬호스트에서만 접속이 가능하도록 하여 다른 도메인으로 접속 시 access denied하여 보안을 강화하였습니다.

다음은 persistQueryClient를 적용하는 방법입니다.

설치

npm i @tanstack/query-persist-client-core @tanstack/query-core  @tanstack/query-async-storage-persister idb

사용

// common/config/vueQueryOptions.ts

import { VueQueryPluginOptions } from '@tanstack/vue-query';
import { persistQueryClient } from '@tanstack/query-persist-client-core';
import { QueryClient } from '@tanstack/query-core';
import { openDB } from 'idb';
import { createAsyncStoragePersister } from '@tanstack/query-async-storage-persister';

// 허용될 HTTPS 프로토콜 주소와 LOCAL 주소
const allowedOrigins = ['http://localhost:8001'];

const DB_NAME = 'my-database'; // DB 이름
const DB_VERSION = 1; // 버전
const STORAGE_KEY = 'my-data'; // 스토리지 키 

// indexedDB 연결
async function connectToDatabase() {
  const db = await openDB(DB_NAME, DB_VERSION, {
    upgrade(database) {
      database.createObjectStore(STORAGE_KEY);
    },
  });
  return db;
}

const storage = {
  getItem: async (key: string) => { /* 캐싱된 데이터 가져오기
      단, 허용된 오리진이 아닐 경우 access denied 됩니다. */
    if (!allowedOrigins.includes(window.location.origin)) {
      throw new Error('Access denied');
    }

    const db = await connectToDatabase();
    const data = await db.get(STORAGE_KEY, key);
    console.log(data);
    return data;
  },
  setItem: async (key: string, values: any) => { // 스토리지 저장
    const db = await connectToDatabase();
    await db.put(STORAGE_KEY, values, key);
  },
  removeItem: async (key: string) => { // 스토리지 삭제
    const db = await connectToDatabase();
    await db.delete(STORAGE_KEY, key);
  },
};


export const vueQueryOptions: VueQueryPluginOptions = {
  queryClientConfig: {
    defaultOptions: {
      queries: {
        // ...query 설정
      },
    },
  },
  clientPersister: (queryClient: QueryClient | any) =>
    persistQueryClient({
      queryClient,
      persister: createAsyncStoragePersister({ storage }),
    }),
  contextSharing: true,
};

작성된 Option을 main.ts의 VueQueryPlugin에 연결합니다.

import { vueQueryOptions } from './common/configs/vueQueryOptions';
...
app.use(VueQueryPlugin, vueQueryOptions); // 옵션 적용
...

새로 고침 후에 혹은 다른 컴포넌트에서 해당 데이터를 getQueryData의 쿼리키로만 불러와도 데이터를 받아볼 수 있습니다.

단, indexedDB가 비동기이기 때문에 지연이 있습니다. 마운트 후 1초 후에 데이터를 불러와서 getQueryData가 새로고침 첫 번째에 undefined였습니다. 로컬 스토리지를 사용하면 지연 없이 데이터를 받아올 수 있으나, 보안에 좋지 않기 때문에 좋은 방법은 아닌 것으로 보입니다.

해결하기 위한 방법으로 persistQueryClient의 데이터가 모두 불러와질 때까지 (약 1초) 기다린 후 데이터를 리턴하는 훅을 제작하는 방법도 있지만 너무 번거로운 방법인 것으로 보여 프로젝트에 실적용하기는 힘들 것으로 보입니다.

만약 미리 불러와서 사용해야 하는 데이터가 있다면 prefetchQuery 후 getQueryData를 하거나, ensureQueryData를 활용하는 방법이 좋을 것으로 보입니다 🙂

'FrontEnd > Vue' 카테고리의 다른 글

[Vue-Cal] Vue.js 캘린더 라이브러리  (0) 2023.07.03
[Vue] requestAnimationFrame  (0) 2023.04.25
[Vue-Query] useMutation  (0) 2023.04.20
[Vue-Query] useQuery  (0) 2023.04.20
[Vue-Query] @tanstack/vue-query  (0) 2023.04.20