Isomorphic library to lazy-load data for React components
- Define & lazy-load component data dependencies and inject them as
props
. - Express/Koa/Hapi-friendly server-side rendering.
- Progressive, client-side rendering.
- Works with React Router.
Similar to ui-router for Angular, React Resolver lets you define & load data dependencies as close to the templates using them as possible: the Components.
You may be asking, how is this different from Relay & GraphQL?
Both projects are working to solve the similar problems:
Data fetching is still a tricky problem, especially as applications become more complicated.
With Relay & GraphQL:
Each component specifies its own data dependencies declaratively using a query language called GraphQL. The data is made available to the component via properties on
this.props
.
(Emphasis my own)
With React Router, whether you use Flux-like Stores, hand-crafted Services, or even isomorphic HTTP libraries like superagent, is up to you.
Once Relay is released, you should be to make a smooth transition (if you'd like!),
as your templates should still be expecting the same data via this.props
.
$ npm install --save react-resolver
var Resolver = require('react-resolver');
// Create an instance
var resolver = new Resolver();
// or, if you prefer factories...
var resolver = Resolver.create();
var Resolver = require('react-resolver');
var UserView = React.createClass({
mixins: [Resolver.mixin],
statics: {
resolve: {
// Return a Promise
user: function() {
return UserStore.find(this.getParams().userId);
},
// or use a Callback
user: function(done) {
request.get(`/users/${this.getParams().userId}`, done);
}
}
},
...
});
Assuming you're using React Router, you'll need to wrap your routes
to maintain context
:
var resolver = require('resolver').create();
var routes = resolver.route(require('./routes'));
This makes it possible for your statics.resolve
props to access
Router.State
, Router.Navigation
, and other contexts.
Because the client supports lazy-loading of components, you can use
React.render
as usual.
The only caveat is, if you're using react-router, you'll need to
wrap your routes with resolver.route
to maintain context:
var Resolver = require('resolver');
var routes = require('./routes');
var resolver = Resolver.create();
Router.run(resolver.route(routes), function(Handler) {
React.render(<Handler />, document.getElementById('app'));
});
On the server, all promises have to be resolved before rendering
and sending the response via resolver.resolve
.
Be sure to create a new instance of the Resolver
per-request to avoid
leaking props to different users!
var Resolver = require('resolver')
var routes = require('./routes');
// Your middleware here...
app.get('/', function(req, res) {
var resolver = Resolver.create();
Router.run(resolver.route(routes), function(Handler) {
resolver.resolve(<Handler />).then(function(handled) {
res.send(React.renderToStaticMarkup(handled));
});
});
});
$ npm install
$ npm link .
$ (cd examples/contacts/ && npm link react-resolver)
$ npm test
- Eric Clemmons ([email protected])