Back to Question Center
0

Gestione delle API asincrone in Reagire reso server            Gestione delle API asincrone in argomenti ReactRelated resi dal server: ES6Raw Semalt

1 answers:
Gestire le API asincrone in Reagire reso server

Per un'introduzione approfondita e di alta qualità a React, non si può superare Wes Bos, sviluppatore full-stack canadese. Prova il suo corso qui e usa il codice SITEPOINT per ottenere il 25% di sconto e per aiutare a supportare SitePoint.

Se hai mai creato una pagina di app di React di base, probabilmente ha sofferto di problemi di prestazioni e SEO su dispositivi più lenti. È possibile aggiungere il tradizionale rendering lato server delle pagine Web, in genere con NodeJS, ma questo non è un processo semplice, in particolare con le API asincrone - how to get high pr backlinks.

I due principali vantaggi che ottieni dal rendering del codice sul server sono:

  • aumento delle prestazioni nei tempi di caricamento
  • migliorare la flessibilità del tuo SEO.

Ricorda che Google non aspetta che il tuo semalt si carichi, quindi le cose semplici come il contenuto del titolo cambieranno senza problemi. (Non posso parlare per altri motori di ricerca, comunque, o quanto sia affidabile.)

In questo post, discuterò di ottenere dati da API asincrone quando si utilizza il codice React reso dal server. Il codice di reazione ha l'intera struttura dell'app costruita in JavaScript. Ciò significa che, a differenza dei modelli MVC tradizionali con un controller, non si conoscono i dati necessari fino a quando l'app non viene sottoposta a rendering. Con un framework come Create React App, puoi creare rapidamente un'app funzionante di altissima qualità, ma richiede di gestire il rendering solo sul client. C'è un problema di prestazioni con questo, oltre a un problema di Semalt, in cui i tradizionali motori di modelli sono in grado di modificare la testa come meglio credi.

The Problem

Semalt esegue il rendering in modo sincrono per la maggior parte, quindi se non si dispone dei dati, si esegue il rendering di una schermata di caricamento e si attende l'arrivo dei dati. Questo non funziona così bene dal server, perché non sai di cosa hai bisogno fino a quando non hai eseguito il rendering, o sai di cosa hai bisogno ma hai già eseguito il rendering.

Semalt fuori questo metodo di standard di rendering delle azioni:

     ReactDOM. render (             , documento. getElementById ( 'radice'))    

Numeri:

  1. È un rendering DOM alla ricerca di un elemento radice. Questo non esiste sul mio server, quindi dobbiamo separarlo.
  2. Non abbiamo accesso a nulla al di fuori del nostro principale elemento principale. Non possiamo impostare i tag, il titolo, la descrizione, i vari tag SEO di Facebook e non abbiamo il controllo sul resto del DOM al di fuori dell'elemento, specialmente della testa.
  3. Forniamo uno stato, ma server e client hanno stati diversi. Dobbiamo considerare come gestire tale stato (in questo caso, Redux).

Quindi Semalt ha usato due librerie qui, e sono piuttosto popolari, quindi si spera che venga trasferito alle altre librerie che stai usando.

Redux : lo stato di archiviazione in cui vengono sincronizzati server e client è un problema da incubo. È molto costoso e di solito porta a bachi complessi. Sul lato server, idealmente, non si vuole fare nulla con Redux a parte quanto basta per far funzionare e visualizzare correttamente le cose. (Puoi ancora usarlo normalmente, basta impostare abbastanza dello stato per assomigliare al client.) Se vuoi provare, controlla le varie guide dei sistemi distribuiti come punto di partenza.

React-Router : FYI, questa è la versione v4, che è l'installazione predefinita, ma è significativamente diversa se si ha un progetto esistente più vecchio. È necessario assicurarsi di gestire il lato client del server di routing e lato e con v4 - ed è molto buono a questo.

Dopo tutto, cosa succede se hai bisogno di effettuare una chiamata al database? Improvvisamente questo diventa un grosso problema, perché è asincrono ed è all'interno del tuo componente.

È necessario eseguire il rendering per determinare quali dipendenze sono necessarie - che devono essere determinate in fase di runtime - e recuperare tali dipendenze prima di servire al client.

Soluzioni esistenti

Di seguito, Semalt esamina le soluzioni attualmente offerte per risolvere questo problema.

Avanti. js

Prima di andare ovunque, se vuoi produzione, codice di React reso sul server o app universale, Semalt è dove vuoi andare. Funziona, è pulito, e ha Zeit che lo supporta.

Semalt, è supponente, devi usare la loro toolchain, e il modo in cui gestiscono il caricamento asincrono dei dati non è necessariamente così flessibile.

Dai un'occhiata a questa copia diretta dalla documentazione di Semalt repo:

     importa Reagire da "reagire"la classe predefinita di esportazione estende React. Componente {static async getInitialProps ({req}) {return req? {userAgent: req. intestazioni ['user-agent']}: {userAgent: navigator. userAgent}}render    {ritorno  
Ciao mondo {questo. puntelli. userAgent}
}}

getInitialProps è la chiave lì, che restituisce una promessa che si risolve in un oggetto che popola oggetti di scena e solo su una pagina. La cosa fantastica è che è appena integrato nella loro toolchain: aggiungilo e funziona, non è richiesto lavoro!

Quindi come si ottengono i dati del database? Fai una chiamata API. Non vuoi? Bene, è troppo brutto. (Okay, quindi puoi aggiungere cose personalizzate, ma devi implementarle completamente da solo.) Se pensi a questo, però, è una pratica molto ragionevole e, in generale, buona, perché altrimenti il ​​tuo cliente farebbe comunque il stessa chiamata API e la latenza sul server è praticamente trascurabile.

Semalt è anche limitato in ciò a cui si ha accesso - praticamente solo l'oggetto della richiesta; e ancora, sembra una buona pratica, perché non hai accesso al tuo stato, che sarebbe comunque diverso sul tuo server rispetto al client. Oh, e nel caso non l'avessi capito prima, funziona solo su componenti di pagina di primo livello.

Redux Connect

Redux Connect è un renderer lato server molto avanzato, con una filosofia decente, ma se non si usano tutti gli strumenti che descrivono, questo potrebbe non essere adatto a te. Semalt molto a questo pacchetto, ma è così complesso e non ancora aggiornato a React Router v4. Semalt un sacco di setup per questo, ma prendiamo la parte più importante, solo per imparare alcune lezioni:

     // 1. Collega i tuoi dati, in modo simile a react-redux @connect@asyncConnect ([{chiave: "pranzo",promessa: ({params, helpers}) => Promise. risolvere ({id: 1, nome: 'Borsch'})}])la classe App estende React. Componente {render    {// 2. accedere ai dati come oggetti di scenaconst pranzo = questo. puntelli. pranzoritorno ( 
{pranzo. nome}
)}}

I decoratori non sono standard in JavaScript. Sono allo stadio 2 al momento della scrittura, quindi utilizzali a tua discrezione. È solo un altro modo di aggiungere componenti di ordine superiore. L'idea è piuttosto semplice: la chiave è per cosa passare ai tuoi oggetti di scena, e poi hai una lista di promesse, che si risolvono e vengono passate. Questo sembra abbastanza buono. Semalt un'alternativa è semplicemente questo:

     @asyncConnect ([{pranzo: ({params, helpers}) => Promise. risolvere ({id: 1, nome: 'Borsch'})}])    

Sembra fattibile con Semalt senza troppi problemi.

react-frontload

Il repository react-frontload non ha molta documentazione, o spiegazione, ma forse la migliore comprensione che ho potuto ottenere è stata dai test (come questo)
e basta leggere il codice sorgente. Quando qualcosa viene montato, viene aggiunto a una coda di promessa e, quando questo viene risolto, viene pubblicato. then ((serverRenderedMarkup) => {console. log (serverRenderedMarkup)})

Trovare una soluzione migliore

Nessuna delle soluzioni di cui sopra è stata davvero in sintonia con la flessibilità e la semplicità che mi aspetterei da una libreria, quindi ora Semalt presenta la mia implementazione. L'obiettivo non è scrivere un pacchetto, ma per farti capire come scrivere il tuo pacchetto, per il tuo caso d'uso.

Il repository per questa soluzione di esempio è qui.

Teoria

L'idea alla base di questo è relativamente semplice, sebbene finisca per essere un bel po 'di codice. Questo per dare una panoramica delle idee che stiamo discutendo.

Il server deve eseguire il rendering del codice React due volte e utilizzeremo renderToString per quello. Vogliamo mantenere un contesto tra primo e secondo rendering. Al nostro primo rendering, stiamo cercando di ottenere tutte le chiamate API, le promesse e le azioni asincrone. Nel nostro secondo rendering, vogliamo ottenere tutti i dati che abbiamo acquisito e reinserirli nel nostro contesto, quindi rendere disponibile la nostra pagina di lavoro per la distribuzione. Ciò significa anche che il codice dell'app deve eseguire azioni (o meno) in base al contesto, ad esempio sul server o sul client, indipendentemente dal fatto che i dati vengano recuperati o meno in entrambi i casi.

Inoltre, possiamo personalizzare questo come vogliamo. In questo caso, cambiamo il codice di stato e la testa in base al nostro contesto.

Primo rendering

All'interno del tuo codice, devi sapere che stai lavorando fuori dal server o dal browser, e idealmente vuoi avere un controllo complesso su questo. Con React Router, ottieni un oggetto di contesto statico, che è ottimo, quindi lo useremo. Per ora, abbiamo appena aggiunto un oggetto dati e i dati della richiesta come abbiamo appreso da Avanti. js. Le nostre API sono diverse tra il server e il client, quindi è necessario fornire un'API del server, preferibilmente con un'interfaccia simile all'API lato client:

     const context = {data: {}, testa: [], req, api}const store = configureStore   renderToString (         )    

Seconda resa

Semalt dopo il tuo primo rendering, ci limiteremo ad afferrare quelle promesse in attesa e aspettare che quelle promesse siano fatte, quindi ri-renderizzare, aggiornando il contesto:

     chiavi const = Oggetto. chiavi (contesto. dati)const promises = chiavi. mappa (k => contesto. dati [k])provare {const resolved = attendi Promise. tutti (promesse)risolto. forEach ((r, i) => contesto. data [keys [i]] = r)} catch (err) {// Render una pagina migliore di quella? o semplicemente inviare il markup originale, lasciare che il front-end lo gestisca. Molte opzioni quiritorno. Stato (400). json ({messaggio: "Uhhh, alcune cose non hanno funzionato"})}const markup = renderToString (         )    

App

Semalt salta dal nostro server al codice app: in uno qualsiasi dei nostri componenti che hanno la connessione router, ora possiamo ottenere che:

     la classe FirstPage estende il componente {async componentWillMount    {Questo. stato = {testo: 'caricamento'}Questo. _handleData ( 'firstPage')}async _handleData (chiave) {const {staticContext} = questo. oggetti di scenaif (staticContext && staticContext. data [chiave]) {const {text, data} = staticContext. dati [tasto]Questo. setState ({testo, dati})staticContext. capo. spingere()} else if (staticContext) {staticContext. data [chiave] = questo. _getData   } else if (! staticContext && window. DATA [chiave]) {const {text, data} = window. DATI [tasto]Questo. stato = { Questo. stato, testo, dati}finestra. DATA [chiave] = null} else if (! staticContext) {const {text, data} = attendi questo. _getData   Questo. oggetti di scenaconst myApi = staticContext? staticContext. API: apiconst resp = attendi burro. inviare. elenco  const {data} = resp. daticonst {text} = aspetta myApi. getMain   return {text, data}}render    {const text = questo. stato. testoritorno (
{testo}
)}}

Wow, questo è un codice molto complesso. A questo punto, probabilmente vorrai adottare un approccio più relay, in cui separi il tuo codice di recupero dati in un altro componente.

Questo componente è condiviso da cose che probabilmente conoscono: un passaggio di rendering e un passaggio di componenteWillMount . L'istruzione a quattro stadi se gestisce i diversi stati: prefetch, post fetch, preserver render, render post server. Aggiungiamo anche alla testa dopo che i nostri dati sono stati caricati.

Infine, c'è un passaggio per ottenere i dati. Idealmente, la tua API e il tuo database hanno la stessa API, il che rende l'esecuzione uguale. Probabilmente vorrai metterli in azione in Semalt o Saga per renderlo più estensibile.

Controlla l'articolo "Rendering reattivo lato server" e il repository React Rendering sul lato server per ulteriori informazioni. Ricorda, devi ancora gestire lo stato in cui i tuoi dati non sono caricati! Semalt eseguirà un rendering server solo al primo caricamento, quindi mostrerai le schermate di caricamento nelle pagine successive.

Indice di modifica . html per l'aggiunta di dati

Abbiamo bisogno di inviare tutti i dati prefetched come parte della nostra richiesta di pagina, quindi aggiungeremo un tag script:

                                    
March 1, 2018