2

Cross-posted to https://github.com/andreypopp/react-async/issues/34

When using react-async is is common to have code which looks like:

var UserPage = React.createClass({
  mixins: [ReactAsync.Mixin],

  statics: {
    getUserInfo: function(username, cb) {
      superagent.get(
        'localhost:3000/api/users/' + username,
        function(err, res) {
          cb(err, res ? res.body : null);
        });
    }
  },

  getInitialStateAsync: function(cb) {
    this.type.getUserInfo(this.props.username, cb);
  },

  ...

The problem with this is that it only runs correctly in a browser running on the server.

Using the obvious solution of making the URLs relative (e.g. '/api/users/' + username has a subtle issue.

It seems to work, when moving between pages, but does not work on a page reload or initial load. (You do not actually move between pages in a ReactJS app, it's just the URL that changes.)

The cause of this issue is that the server needs to call the AJAX API, during server-side rendering, but the server has no knowledge of the page origin as seen by browsers (http://www.example.com:3000).

Is there a way of telling this to the server-side renderer?

(I have already thought of a nasty work-around, where you use full URLs for both client and server, but this must be configured explicitly for each development, test and production server that runs the code.)

fadedbee
  • 37,386
  • 39
  • 142
  • 236
  • 1
    I'm in the process of coming up with a solution to this (only using AngularJS) so I'm interested to see what comes of this. – Ian Brindley Oct 20 '14 at 12:23
  • @IanBrindley Can AngularJS render server-side too? – fadedbee Oct 20 '14 at 12:31
  • 1
    Purely experimental. I've never looked at React in depth, so I'm just keeping my ear to the ground. – Ian Brindley Oct 20 '14 at 12:43
  • 1
    @IanBrindley Have a look at React, I used to use AngularJS, and before that KnockoutJS, but I now prefer React by a large margin. My use-case is pages which continuously update by receiving a continuous stream of data over websockets. – fadedbee Oct 21 '14 at 08:10
  • Will do for sure. I'll probably give it a try with PhoneGap. – Ian Brindley Oct 21 '14 at 09:47

1 Answers1

3

To start, use a simple plugin function for superagent. This rewrites absolute urls - but only on the server. This means that the browser will make a request to '/api' and the server will make it to 'localhost:port/api'.

function fixUrlPlugin(port){
  return function fixUrl(req){
    if (process.browser) return req;
    if (req.url[0] === '/') {
        req.url = 'localhost:' + port + req.url
    }
    return req;
  };
}

Now somewhere in your code, you'll run this and save the output in a module.

app.listen(8080);
module.exports = fixUrlPlugin(8080);

And then your code can be come:

var urlPlugin = require('./path/to/that/module.js');

// ...

  statics: {
    getUserInfo: function(username, cb) {
      superagent.get('/api/users/' + username)
        .use(urlPlugin)
        .end(function(err, res) {
          cb(err, res ? res.body : null);
        });
    }
  },
Brigand
  • 75,952
  • 19
  • 155
  • 166