Fare promesse sospendibili

Mar 21 2023
Questo è un articolo in due parti in cui ci concentriamo prima sulla comprensione delle basi dei motivi per utilizzare l'API Suspense e nella parte successiva discuteremo su come utilizzare i nuovi hook Suspense per Meteor. Spiegherò come far entrare in modalità suspense le tue promesse e cosa serve per arrivarci.

Questo è un articolo in due parti in cui ci concentriamo innanzitutto sulla comprensione delle basi dei motivi per utilizzare l'API Suspense e, nella parte successiva, discuteremo su come utilizzare i nuovi hook Suspense per Meteor .

Spiegherò come far entrare in modalità suspense le tue promesse e cosa serve per arrivarci.

Raccomando due articoli per la teoria su questo lato che mi hanno aiutato a capire come React gestisce i valori asincroni. Uno è di Dan Abramov - Algebraic Effects for the Rest of Us , e l'altro è di Radosław Miernik - On throwin React

Perché usare la suspense?

Come spiega questo buon articolo , Suspense ci offre due grandi caratteristiche:

  • La strega del codice dichiarativo significa che React Suspense semplifica il processo di scrittura del codice dell'interfaccia utente consentendo agli sviluppatori di dichiarare l'aspetto dell'interfaccia utente piuttosto che scrivere codice che indica all'interfaccia utente come eseguire il rendering passo dopo passo. Un esempio di questa funzione è la rimozione della isLoadingvariabile use. Inserendo questa variabile sopra il codice dell'interfaccia utente, gli sviluppatori possono garantire che il loro codice sia sincronizzato con l'interfaccia utente. Ciò elimina la necessità di ifdichiarazioni imbarazzanti.
  • Migliore esperienza dell'utente finale con Suspense. Puoi utilizzare il motore di rendering simultaneo appena aggiunto in React. Questa funzione Suspense offre all'utente finale una migliore sensazione di come l'interfaccia utente appare e agisce perché la reazione aggiornerà solo ciò di cui ha bisogno.

Ora spiegherò come funziona. Innanzitutto, avrai bisogno di una mappa della cache per memorizzare le tue promesse. Poiché React sospende, la promessa e poi la mantiene, hai bisogno di un modo per tenere traccia di questa specifica promessa (questa era una parte con cui ho faticato molto a capire, deve essere esattamente la stessa promessa ogni volta). Se non c'è alcun valore nella chiave data, l'hook creerà una voce nella mappa con this promisee throwit. Qui è dove avviene la magia. L' suspensifyhook assomiglia allo snippet qui sotto nella sua prima esecuzione:

function suspensify<T>(key: string, promise: Promise<T> | null, deps: DependencyList = [], lifespan = 0): T {
  const cached = cacheMap.get(key)
	**//    ˆˆˆ this is undefined. all code below is not ran
  /* ... code ...*/
 const entry: Entry = {
    deps,
    promise: new Promise((resolve, reject) => { // here you work in your promise / waitable value. remember to set the result and error
      promise
        .then((result) => {
          entry.result = result
          resolve(result)
        })
        .catch((error) => {
          entry.error = error
          reject(error)
        })
    })
  }
  
  cacheMap.set(key, entry)
  throw entry.promise
// ˆˆˆˆthis is where we jump into the fallback
}

Bene, quando l'hook viene eseguito di nuovo (sì, è così che funziona la suspense), andremo a quello ifche era sopra la creazione della voce:

function suspensify<T>(key: string, promise: Promise<T> | null, deps: DependencyList = [], lifespan = 0): T {
  const cached = cacheMap.get(key)
  //    ˆˆˆ now we have a value here
  useEffect(() =>
    () => {
      setTimeout(() => {
        if (cached !== undefined && isEqual(cached.deps, deps)) cacheMap.delete(key)
				// ˆˆˆˆclean when the hook unmounts.
      }, lifespan)
    }, [cached, key, ...deps])
  
  if (promise === null) return null // we talked about this one
  if (cached !== undefined) {
    if ('error' in cached) throw cached.error
              // ˆˆˆˆtrigger error boundary
    if ('result' in cached) {
      const result = cached.result as T
      setTimeout(() => {
        cacheMap.delete(key)
      }, lifespan)
      return result // resolve suspense
    }
    throw cached.promise // as we have not got any result or err we should wait a bit more
  }
  
/* ... code ...*/
}

Ed ecco fatto, hai imparato qualcosa su come funziona la suspense e su come puoi usarla oggi per gestire le tue promesse.

React Query supporta già Suspense e Relay è il nostro esempio più eccezionale di Suspense API nella pratica.

Se sei interessato a ciò che hai visto qui e vuoi vedere le versioni implementate di una libreria utilizzando l'API di suspense, puoi controllare il prossimo capitolo di questa serie di articoli, dove vengono mostrati i nuovi ganci di suspense per Meteor .