Fermer

mai 10, 2019

IndexedDB – Une base de données dans le navigateur (partie 2)


Lorsque le stockage local et les cookies atteignent leurs limites, lorsque la nature bloquante des threads ralentit votre application, il est temps de passer à IndexDB. Mais pourquoi vivre avec l'API de bas niveau qui peut être maladroit pour se faire comprendre? Accédez à PouchDB et commencez à tirer parti de ce stockage de navigateur asynchrone et performant aujourd'hui.

Il existe de nombreuses manières de stocker des données côté client. Nous avons couvert Stockage, sessionStorage et les cookies dans Partie 1 de cet article mais ce n'est pas là que ça se termine! Les navigateurs modernes proposent une autre approche du stockage des données côté client, offrant des lectures et des écritures asynchrones avec une interface légèrement confuse. De quoi est-ce que je parle? Non, pas Web SQL, qui est déconseillé et ne doit pas être utilisé. Je parle de IndexedDB !

Dans cet article, nous verrons comment utiliser IndexedDB (avec la bibliothèque PouchDB) pour stocker des brouillons pouvant ensuite être synchronisés avec notre API à être stocké en permanence. Fermer accidentellement votre navigateur? Jamais peur! Le projet a été mis à l'abri dans IndexedDB.

Le code source de ce projet est disponible sur https://github.com/leighhalliday/leigh-notes-web . La version finale de cette application se trouve à https://leigh-notes-web.herokuapp.com/ .

Interface difficile

J'ai mentionné ci-dessus qu'il est difficile de travailler avec IndexedDB, et même cette explication utilise une API légèrement modifiée (qui a été promise) pour interagir avec elle. Pour cette raison, de nombreuses personnes ont créé des bibliothèques construites sur IndexedDB pour simplifier les choses. Les bibliothèques populaires comprennent localForage Dexie.js BID-keyval et la bibliothèque que nous allons couvrir dans cet article, PouchDB . .

Connexion à la base de données

De la même manière que le code serveur / côté serveur doit se connecter à la base de données, nous devons également nous connecter à notre base de données PouchDB. Comme il s'agit d'un code spécifique au client et que Next.js est également exécuté sur le serveur, j'ai une vérification en place pour ne renvoyer une connexion à la base de données que si nous sommes dans le navigateur. nous vous suggérons de vous connecter à une note appelée "notes", qui sera créée si elle n'existe pas encore.


 import  PouchDB  de   "pouchdb" ; 

 const   getDb   =   ()   =>   {
   if   ( processus .  navigateur )   {
     return   new   PouchDB  ( "notes"   { auto_compaction :   true  } ) ; 
  } 
} ; 

Jusqu'à présent, le composant que nous construisons et qui donne aux notes l'aspect suivant:

 class   Index   s'étend   Réagissez .  Composant   {[19659043] statique   async   getInitialProps  ( { jeton } )   {
     retour   { jeton   } ; 
  } 

  
  state  =   {
    draftNotes :   {} 
    savedNotes :   {} 
  } ; 

  
  db  =   getDb  () ; 

  
} 

Lecture des notes

Lorsque notre composant est monté, nous souhaitons charger le DraftNotes . ] de PouchDB et peupler l'état avec eux.

 composantDidMount  ()   {
   ceci .  loadDraftNotes  () ;  
   this .  loadSavedNotes  ()   
} 

La ​​fonction loadDraftNotes est lue en premier tousDocs . le DB qui nous rend un objet résultat. Après avoir extrait le doc (la note réelle) de chaque ligne, puis l'avoir inversé pour que le dernier projet de note figure en haut de la liste, nous pouvons le placer dans l'état.

 loadDraftNotes  =   async   ()   =>   {
   const  result  =   attend   ceci .  est vide. db .  allDocs  ( { include_docs :   true  } ) ; 
   const  =  résultat .  rangées .  carte  ( rangée  =>  rangée . .  doc  ]) .  reverse  () ; 
   ceci .  setState  ( { projetNotes } ) ; 
} ; 

Ajout et mise à jour de notes

Lors de la création d'une nouvelle note, vous devez disposer d'un colonne unique _id requise par PouchDB… nous utilisons une chaîne ISO de la date actuelle dans ce cas. Tout d'abord, nous allons annexer l'état draftNotes, en ajoutant notre nouvelle note au début du tableau, puis appeler la fonction db.put (note) qui insère la nouvelle note dans la base de données.

  createNote   =   ()   =>   {
   const  note  =   {
    _id :   new   Date  () .  toISOString  () 

    body : "" } ; const draftNotes = [ note ... . ] this . state . draftNotes ] ; cette . setState ( { draftNotes } ) ; ceci . db . put ( note ) ; ]} ;

La ​​mise à jour est légèrement plus compliquée que l'insertion, mais ce n'est pas si mal! Étant donné l'index de la note de notre tableau draftNotes et le corps mis à jour, nous pouvons tout d'abord mettre à jour l'état (avec un peu d'aide de la bibliothèque immuable Immer).

Après En mettant à jour l'état, nous allons utiliser l'index pour trouver la propriété _id nécessaire à PouchDB pour le lire dans la base de données. Après avoir lu la note de la base de données, nous pouvons mettre à jour sa propriété body puis appeler put pour mettre à jour la base de données avec nos modifications.

Même si nous avons utilisé le put pour insérer une nouvelle note et mettre à jour une note existante, PouchDB est assez intelligent pour savoir laquelle vous essayez de faire en raison de son attribut unique _id .

 updateNote  =   async   ( index  corps )   =>   {
   ce .  set-state  (
     produire  ( draft  =>   {
      draft .  draftNotes  [ index ] .  body  =  corps ; 
    } ) [19659034]) ; 

   const  noteId  =   cette .  état .  projet de notes  [ index  ] .  _id ; 
   const  note  =   attend   cette .  db . . 19659012] ( noteId ) ; 
  note .  body  =  body ; 
   cette .  db .  mis  [1359000] note ) ; 
} ; 

Suppression des notes

À un moment donné, vous voudrez peut-être enregistrer vos brouillons sur le serveur. Dans cet exemple, j'ai appelé sync .

  1. Publiez la note via AJAX sur notre API, enregistrez-la dans notre base de données de production.
  2. Supprimez la note de la base PouchDB locale

. Après avoir parcouru toutes les notes, nous peut appeler loadDraftNotes et loadSavedNotes à nouveau pour rafraîchir l'état.

 syncNotes  =   async   () (19659012) =   =   ] {
   const  promet  =   ce .  état .  projetNotes
    .  filtre  ( note  =>  note .  corps ) 
    .  carte  [19659]. 19659146] async  note  =>   {
       attend   cette .  postNoteToApi  ( note ) ; ] attendez   ce .  deleteNote  ( note ) ; 
    } ) ; 

   wait  wait  Promise .  all  ( promesses ) ; 

   ceci .  loadDraftNotes  ()    ] this .  loadSavedNotes  () ; 
} ; 

De nombreuses promesses se réalisent ici! Vous vous retrouvez avec un tableau d'entre eux et, avec vous attendez Promise.all (promises) vous pouvez attendre qu'ils soient tous résolus. Jetons un coup d’œil à ce que postNoteToApi (note) fait. C'est une requête POST AJAX assez simple qui utilise Axios avec l'API, transmettant le jeton JWT dans l'en-tête Authorization afin qu'il sache qui nous sommes.

  postNoteToApi   =  note  => [19659016] {
   const   { jeton }   =   ce .  étais ; 
   retour  Axios  .  post  (
     "https://leigh-notes-api.herokuapp.com/notes" 
     {
      note :   { body :  note .  body } 
    } 
     { en-têtes :   { Autorisation :   `Porteur:  $ { jeton }  `        ]} 
  ) ; 
} ; 

Une fois que nous avons posté la note sur l'API, nous pouvons la supprimer de notre PouchDB local, qui est ce que deleteNote (note ) fait:

 deleteNote  =   async  note  =>   {
   const  doc  =   à attendre   this .  db .  get  ( note .  _id ) ; 
   à attendre   cette [19659012].  db .  remove  ( doc ) ; 
} ; 

Les notes UI

Nous ' J'ai beaucoup regardé l'indiv fonctions habituelles jusqu’à présent, mais nous n’avons pas encore jeté un œil à quoi ressemble l’interface utilisateur, ce qui est réellement rendu.

 rend  ()   {
const { jeton } = ce . accessoires ;
const { projet de notes




Source link