Isomorphic JS - httpRequest client side only
Asked Answered
M

1

6

Question about store data population in isomorphic flux apps. (I'm using react, alt, iso and node but theory applies to other examples)

I have a flux 'store' (http://alt.js.org/docs/stores/) that needs to get data from an api:

getState() {
   return {
       data : makeHttpRequest(url)
   }
}

and as the user navigates through the SPA, more data will be loaded via http requests.

I want this app to be isomorphic so that I can render the apps full html including latest data server side and return it to the user for fast initial page load.

react.renderToString() lets me render the app as html, and I can seed the data using alt&iso like:

storeData = { "MyStore" : {"key" : "value"}}; // set data for store
alt.bootstrap(JSON.stringify(storeData || {})); // seed store with data

var content = React.renderToString(React.createElement(myApp)); // render react app to html

The problem is that I will see errors when running the js server side as the store will want to make a http request which it wont be able to do (as xmlhttprequest wont exist in node)

Whats the best way to solve this problem?

The only solution I can think of would be to wrap the httprequest from the store with:

var ExecutionEnvironment = require('react/lib/ExecutionEnvironment');

    ...

    if (ExecutionEnvironment.canUseDOM) {
        // make http request
    } else {
        // do nothing
    }

Any better ideas? Thanks in advance.

Modillion answered 9/7, 2015 at 15:5 Comment(4)
Add more information please! E.g: code samples, particular errors associated with the questionLubbock
added code snippet and more detail - let me know if there is anything elseModillion
Why not use a get request for the data instead of mocking AJAX in the backend? The whole point of AJAX is that you don't want to reload the page on front-end. Because you're doing a backend rendering, just send a get/post request to the resource, parse your data accordingly and render it before sending to client.Lubbock
Yes. The problem is that I want to render the data both 'back' and 'front' end, so the first time the user hits the page it will be rendered BE, and then subsequent data loads will come from the client (slightly over simplified but close enough). The client side rendering can be done by a GET request from the client, and the SS rendering can be done via internal api call,the problem is that when the react store is run server side, it will attempt to make a http call which it wont be able to do (without adding some kind of support as per iSchluff s answer below.Modillion
U
2

I would recommend hooking into your Ajax library or XMLHttpRequest directly if you are running serverside. Just shim it with code that supplies data directly from your database or application.

A quick example:

var noop= function(){}

window.XMLHttpRequest= function(){
    console.log("xhr created", arguments);
    return {
        open: function(method, url){
            console.log("xhr open", method, url);
            // asynchronously respond
            setTimeout(function(){
                // pull this data from your database/application
                this.responseText= JSON.stringify({
                    foo: "bar"
                });
                this.status= 200;
                this.statusText= "Marvellous";
                if(this.onload){
                    this.onload();
                }
                // other libs may implement onreadystatechange
            }.bind(this), 1)
        },
        // receive data here
        send: function(data){
            console.log("xhr send", data);
        },
        close: noop,
        abort: noop,
        setRequestHeader: noop,
        overrideMimeType: noop,
        getAllResponseHeaders: noop,
        getResponseHeader: noop,
    };
}

$.ajax({
    method: "GET",
    url: "foo/bar",
    dataType: "json",
    success: function(data){
        console.log("ajax complete", data);
    },
    error: function(){
        console.log("something failed", arguments);
    }   
});

http://jsfiddle.net/qs8r8L4f/

I whipped this up in the last 5 minutes mostly using the XMLHTTPRequest mdn page

However if you are using anything not directly based on XMLHttpRequest or explicitly node aware (like superagent) you will probably need to shim the library function itself.

Other work to do on this snippet would be implementing errors and different content types.

Unblown answered 9/7, 2015 at 15:22 Comment(2)
So there is this which imitates the xmlhttprequest on node npmjs.com/package/xmlhttprequest which could be conditionally loaded.Modillion
Any examples of 'shimming' the request in this way?Modillion

© 2022 - 2024 — McMap. All rights reserved.