making restful api call from react js

kobe picture kobe · Apr 29, 2015 · Viewed 33.9k times · Source

I am doing a POC for isomorphic javascript application to render html from the server side. The POC is working with simple html, but I want to make an api call and get the json response and send to the render function. I tried various ways but it is not working. Can one of you please let me know where I am missing.

I am very new to react js and any help will be really appreciated

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>
        )
      }

  });

Answer

Bogdan Savluk picture Bogdan Savluk · Apr 29, 2015

Fetching inside of component using componentWillMount is not a right place, in case when you need to render server side. You need to somehow move it out form component, and pass actual data as props after it is fetched - for example as @JakeSendar suggested in his answer.

I have some experience doing isomorphic app with React, and the main problem I faced is how to wait until all data would be loaded before first render

As @FakeRainBrigand already mentioned in comments, there is not only one way to do this, and it depends from your requirements.

There is few ways to do build an isomorphic app, the some interesting from my perspective is: https://github.com/webpack/react-starter and http://fluxible.io/

But, the most elegant way to do this, as I figured out for myself - is to organise asynchronous rendering for react components, in particular using RxJS.

In general my application is structured as following:

  1. views - React components without any logic (just a view)
  2. models - Observables with current state (initial data is loaded using superagent, then combined with other models and/or actions results). In simple case it is something like:

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

  3. actions(or intents) - Observers used to collects user input, do something, and dispatch action results to subscribers models and/or other actions. In simple case something like:

    updatesSubject = new Rx.Subject();

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

  4. components - Observables(stream of virtual DOM elements) combined from models, other components and actions (I have a note about this, explaining how and why to create Observable React elements with RxJS), also now I am planning to add partial components (tuple from: react component, observables, observers, and properties. partially filled with using DI)

  5. router - component responsible to handling location changes, in general main feature is to map location changes to stream of virtual DOM elements and meta information. But in details, it is bit more complicated in my case(url generation, active url highlighting, handling scrolls when navigating, also it has possibility of nested routes and multiple views)

All this is assembled together using DI container, in my case similar to angular2 DI container, but a lot simplified for my specific needs.

Components, models and actions are created using DI.

On server side application is like this:

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)
          });
       });
}

and similar on client side:

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)
   });

In comparison to flux, it is more declarative and more powerful way to organise app. And in case of isomorphic app - for me, it looks much better that various hacks with flux. But of course there is drawbacks... - it is more complicated.

Likely later, I will opensource all this, but for now - it is not quite ready to be published.

UPD1:

Original answer is a bit outdated(later I plan to update it), and I have some progress in this area.

Links to code mentioned above, already opensourced:

  • DI container: di1
  • Container for react componentns(connecting view to observables and obsrvers): rx-react-container
  • Starter template, for implementing isomorphic widgets, using RxJS and React, and libraries above: Reactive Widgets

About complete application(work still in progress, and documentation there is not quite good, but in general it should be clear):

  • Router built especially for isomophic reactive applications router1 and react components to use it router1-react
  • Application template with router and all libraries mentioned above: router1-app-template