2015-04-29 10 views
22

Sto facendo un POC per un'applicazione javascript isomorfa per il rendering di html dal lato server. Il POC funziona con semplice html, ma voglio fare una chiamata api e ottenere la risposta JSON e inviare alla funzione di rendering. Ho provato vari modi ma non funziona. Può uno di voi per favore fatemi sapere dove mi sto perdendo.che effettua la chiamata api di riposo da reacs js

Sono molto nuovo a reagire js e qualsiasi aiuto sarà molto apprezzato di renderToString metodo

loadCategoriesFromServer: function() { 
     var self = this; 

// get walking directions from central park to the empire state building 
    var http = require("http"); 
    url = "api url here"; 
     var request = http.get(url, function (response) { 
      // data is streamed in chunks from the server 
      // so we have to handle the "data" event  
      var buffer = "", 
       data, 
       route; 

      response.on("data", function (chunk) { 
       buffer += chunk; 
      }); 

      response.on("end", function (err) { 

       data = JSON.parse(buffer); 

       //console.log(data.d); 
       //console.log(data.d.Items); 
       self.setState({ 
        categories: data.d.Items 
       }); 
      }); 
     }); 
    }, // load from server end 

    getInitialState: function() { 
     return { categories: [] }; 
    }, 

    componentWillMount: function() { 
     console.log("calling load categories") 
     this.loadCategoriesFromServer(); 
    }, 
render: function() { 

     //console.log("data"); 
     //console.log(this.state.categories); 

     var postNodes = this.state.categories.map(function (cat) { 
      console.log(cat); 
     }); 

     return (
      <div id="table-area"> 
      //i want to paint the data here.. 
      </div> 
     ) 
     } 

    }); 
+2

La parte isomorfa è complicata ... non esiste un modo giusto per farlo, e il modo giusto per voi dipende da molte variabili dal router che si utilizza, dal modo in cui il server è organizzato, alle modalità in di cui hai bisogno per recuperare i dati, al livello di astrazione con cui sei a tuo agio. – FakeRainBrigand

+0

@FakeRainBrigand hai qualche esempio semplice? tutto quello che ho bisogno di fare una semplice API e attendere la risposta e il dolore è così. Ho fatto qualcosa, ma il rendering non è in attesa finché non viene effettuata la chiamata – kobe

+0

@FakeRainBrigand, in pratica sto seguendo l'esempio di seguito. https://github.com/DavidWells/isomorphic-react-example, l'unica differenza è che voglio i dati dinamici dalla chiamata api. – kobe

risposta

3

reagire (per il rendering dei componenti sul server) è sincrono. Pertanto, qualsiasi attività asincrona, come la richiesta API, sarà ancora in sospeso al momento del rendering del componente.

Ci sono un paio di modi per risolvere questo problema, a seconda se si desidera o meno recuperare i dati sul server o sul client.

Se si sceglie di recuperare i dati sul server, spostare prima la logica della richiesta api al di fuori del componente. Quindi, effettua il rendering del componente nel callback, passando i dati recuperati come prop. Sembrerebbe qualcosa di simile:

response.on("end", function (err) { 
    var data = JSON.parse(buffer); 
    var markup = React.renderToString(Component({categories: data})); 
}); 

Dentro il componente, devi essere in grado di accedere ai dati tramite this.props.categories.

L'altra opzione è gestire la richiesta API sul client. Dovresti effettuare una richiesta AJAX in componentDidMount e impostare lo stato del componente dai dati recuperati. Sembrerebbe molto simile a quello che hai ora, la differenza principale è che la tua logica di richiesta vivrebbe in componentDidMount (async, chiamata sul client) anziché componentWillMount (non asincrona, chiamata sul server).

5

Il recupero interno del componente utilizzando componentWillMount non è il posto giusto, nel caso in cui sia necessario eseguire il rendering lato server. Devi in ​​qualche modo spostarlo dal componente del modulo e passare i dati reali come oggetti di scena dopo che è stato recuperato, ad esempio come suggerito da @JakeSendar nella sua risposta.

Ho una certa esperienza facendo app isomorfi con Reagire, e il problema principale che ho riscontrato è il modo di aspettare fino a quando tutti i dati saranno caricati prima del primo render

Come @FakeRainBrigand già accennato nei commenti, non v'è una sola modo per farlo, e dipende dalle tue esigenze.

Ci

è alcuni modi di fare costruire un app isomorfica, il qualche interessante dal mio punto di vista è: https://github.com/webpack/react-starter e http://fluxible.io/

Ma, il modo più elegante per fare questo, come ho capito per me stesso - è quello di organizzare rendering asincrono per reagire componenti, in particolare utilizzando RxJS.

In generale la mia domanda è strutturata come segue:

  1. vista - React componenti senza alcuna logica (solo una vista)
  2. modelli - osservabili con lo stato attuale (dati iniziale viene caricato utilizzando superagent, allora combinato con altri modelli e/o risultati di azioni). In caso semplice è qualcosa di simile:

    Rx.Observable.defer(fetchData).concat(updatesSubject).shareReplay()

  3. azioni (o gli intenti) - Gli osservatori utilizzati per raccoglie l'input dell'utente, fare qualcosa, ed i risultati di azione spedizione verso modelli di abbonati e/o altre azioni. Nel semplice caso qualcosa di simile:

    updatesSubject = new Rx.Subject();

    action = new Rx.Subject(); action.switchMap(asyncRequest).subscribe(updatesSubject)

  4. componenti - osservabili (flusso di elementi DOM virtuali) combinato dai modelli, altri componenti e azioni (I have a note about this, explaining how and why to create Observable React elements with RxJS), anche ora sto progettando aggiungere componenti parziali (tupla da: reagire componente, osservabili, osservatori e proprietà parzialmente riempiti con l'uso di DI)

  5. router - componente responsabile a portata di mano modifiche di posizione ling, in generale, la caratteristica principale è quella di mappare le modifiche di posizione al flusso di elementi DOM virtuali e meta informazioni. Ma nei dettagli, è po 'più complicato, nel mio caso (generazione url, url attiva l'evidenziazione, la movimentazione rotoli Durante la navigazione, inoltre ha possibilità di percorsi nidificate e viste multiple)

Tutto questo è assemblato insieme usando DI contenitore, nel mio caso simile a angular2 DI container, ma molto semplificato per le mie esigenze specifiche.

Componenti, modelli e azioni vengono creati utilizzando DI.

Su richiesta lato server è come questo:

var rootInjector = new Injector(); 
// setup server specific providers 
rootInjector.provide(..., ...) 

app.get('/*', function(req,res){ 
    var injector = rootInjector.createChild(); 
    // setup request specific providers 
    injector.provide(..., ...); 

    injector.get(Router) 
     .first() 
     .subscribe(function(routingResult){ 
      res.render('app', { 
       title: routingResult.title, 
       content: React.renderToString(routingResult.content) 
      }); 
     }); 
} 

e simile sul lato client:

var rootInjector = new Injector(); 
// setup server specific providers 
// actually this is omitted in my case because default providers are client side 
rootInjector.provide(..., ...) 
contentElement = document.getElementById('#content'); 

rootInjector.get(Router) 
    .subscribe(function(routingResult){ 
     document.title = routingResult.title; 
     React.render(routingResult.content, contentElement) 
    }); 

Rispetto al Flux, è più dichiarativo e il modo più potente per organizzare app. E in caso di app isomorfa - per me, sembra molto meglio che vari hack con flusso. Ma naturalmente ci sono degli svantaggi ... - è più complicato.

Probabilmente più tardi, aprirò tutto questo, ma per ora non è ancora pronto per essere pubblicato.

UPD1:

risposta originale è un po 'obsolete (poi ho intenzione di aggiornarlo), e ho qualche progresso in questo settore.

Convenzionale codice di cui sopra, già opensourced:

  • DI contenitore: di1
  • Contenitore per reagire componentns (collegamento vista osservabili e obsrvers): rx-react-container
  • modello avviamento, per attuare i widget isomorfi , utilizzando RxJS e React e librerie sopra: Reactive Widgets

Informazioni sull'applicazione completa (Lavori ancora in corso, e la documentazione non v'è abbastanza buona, ma in generale dovrebbe essere chiaro):

  • Router costruito appositamente per le applicazioni reattive isomophic router1 e reagire componenti di usarlo router1-react
  • modello di applicazione con router e tutte le librerie di cui sopra: router1-app-template
+0

Ho pensato che in questo caso il lato server restituirà sempre JSON e tutti i rendering dei componenti di reazione saranno sul lato client? –

+0

@ChandlerLee in alcuni casi si potrebbe voler rendere tutto il lato pagina del server html (per accorciare il tempo di caricamento, o solo per il SEO) ... reagire è in grado di fare ciò, inoltre può riutilizzare il modulo html quando si inizializza il lato client app –

+0

quando dici "visualizzazioni" stai parlando di "visualizzazioni controller" allora? Stai usando dei modelli html? Come appaiono i tuoi file o modelli .html e quali sono in essi, incorporate la libreria di reazione nel modello? – PositiveGuy

0

si dovrebbe usare superagent, funziona davvero bene per me, anche vi manca la parte più importante, è necessario utilizzare flusso per recuperare i dati fro m un server, il flusso è il modo consigliato da Facebook, è piuttosto facile da usare flux architecture.

+3

alcuni credono che Flux o Redux sia anche gonfio e facciano bene senza di esso. E scusa, ma l'architettura di Flux NON è facile per chi è nuovo per la prima volta, è una grande curva di apprendimento in anticipo. Smettila di dire "tutto è facile" quando sai che anche tu hai faticato per impararlo ... ti garantisco che non hai avuto alcun flusso finché non l'hai guardato per una settimana o due. Se dici di non aver mentito. – PositiveGuy

+0

testate le vostre applicazioni? – PositiveGuy

Problemi correlati