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