IndexedDB с Vue 3: предоставить / внедрить - PullRequest
0 голосов
/ 20 июня 2020

По сути, я хочу экспортировать экземпляр класса, у которого есть свойство, содержащее экземпляр базы данных indexedDB, и несколько методов для выполнения операций чтения / записи db. С помощью экспорта я могу provide/inject этот экземпляр между компонентами в разных деревьях компонентов.

useDb.ts

class DB {

  db: IDBDatabase;

  constructor(db: IDBDatabase) {    
    this.db = db;
  }

  check() {
    console.log('checking');
    console.log(this.db);    
  }

  // ...other methods...

}

Чтобы получить доступ к экземпляру indexedDB, вам нужно вызвать indexedDB. open () метод. Этот метод является асинхронным, но использует обратные вызовы, а не обещания, и возвращает не экземпляр базы данных, а объект запроса. Чтобы получить фактический экземпляр базы данных, вы присоединяете слушателя к обратному вызову onsuccess:

Пример:

const req = indexedDB.open(DB_NAME, DB_VERSION);

req.onsuccess = (event: Event) => { 
  const dbInstance = (event.target as IDBOpenDBRequest).result;  // Actual instance of db to work with     
};

Поскольку он асинхронный, но не использует обещания, я заключаю его в обещание и экспортирую :

useDb.ts

// class DB here...

export default (async () => {

  // IndexDB Open request promise-ified
  function dbRequest(): Promise<IDBDatabase> {

    return new Promise( (resolve, reject) => {    

      const req = indexedDB.open(DB_NAME, DB_VERSION);

      req.onsuccess = (event: Event) => { 
        const dbInstance = (event.target as IDBOpenDBRequest).result;       
        resolve(dbInstance);
      };

      req.onerror = (event: Event) => {         
        const error = (event.target as IDBOpenDBRequest).error;
        reject(error);
      }
    })
  }

  // Make sure browser/device supports indexedDb
  if(window.indexedDB) { 

    try {
      const dbInstance = await dbRequest();

      // Instantiate DB class here passing in the actual database instance to the constructor
      const db = new DB(dbInstance); 
      return db;   

    } catch(e) {
      // TODO: Handle db request error   
      console.log(e);
      return null;
    }
  } else {
    return null;
  }

})();

Итак, в моем приложении. vue я мог:

app. vue

import { defineComponent, provide } from '@vue/composition-api'
import useDb from './use/useDb'


export default defineComponent({
  name: 'App',

  setup() {    
    provide('db', useDb);
  }
})

Проблема, с которой я столкнулся, заключается в том, что поскольку экземпляр db экспортируется как обещание, у меня нет доступа ни к одному из методов экземпляра класса DB. Это не сработает:

random-component. vue

import { defineComponent, inject } from '@vue/composition-api'

export default defineComponent({
  name: 'Random',

  setup() {    
    const $db = inject('db');

    function testDb() {
      $db.check() // Property 'check' does not exist on type 'Promise<DB | null>'.
    }
  }
})

Я знаю, что могу "$ db.then (db => ...)" в компонентах, но это не похоже на go правильный способ об этом.

Как я могу заставить эту работу работать, или есть лучший способ выполнить sh внедрение зависимостей асинхронной службы?

...