Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

react-resolver

Package Overview
Dependencies
Maintainers
1
Versions
34
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

react-resolver

Async-rendering & data-fetching for universal React applications

  • 2.0.2
  • Source
  • npm
  • Socket score

Version published
Weekly downloads
2.4K
increased by31.03%
Maintainers
1
Weekly downloads
 
Created
Source

React Resolver https://img.shields.io/npm/v/react-resolver.svg

Async-rendering & data-fetching for universal React applications.

React Resolver let's you define data requirements per-component and will handle the nested, async rendering on both the server & client for you.


Why?

React's rendering is synchronous by design. As a result, rendering on the server is left as an exercise for the rest of the community to figure out.

There are some cludgy solutions for this, most of which require having fat handlers components controllers at the top of your application that are responsible for marshalling data for all components under them.

For a non-trivial application, this means mixing concerns between your specialized components and the controllers, which is conceptually difficult and programmatically annoying to maintain.

How?

The simplest example is a pure, client-side only application. Afterwards, we can change a few lines to turn this into a universal application.

If you're the visual type, view the examples:

Dependencies

  • React v0.13 or v0.14

For browsers that don't natively support Promises, use ES6 Promises.

1. Install react-resolver

$ npm install --save react-resolver

2. Decorate Components with Data

Suppose you have the following Stargazer component to render a Github user's profile:

export default class Stargazer extends React.Component {
  static propTypes = {
    user: React.PropTypes.object.isRequired,
  }

  render() {
    /* Render profile from this.props.user */
  }
}

In 2014, you would use componentWillMount to fire off an AJAX request for the profile, then use setState to trigger a re-render with the data.

This won't work on the server-side, and it's annoying to test.

According to most universal boilerplates, we'd put static fetchData() function in our component for a middleware or library to handle, rendering the component when data comes back.

This only works for fat controllers at the top of your application, usually defined by a React Router <Route>.

Instead, let's decorate it:

import { resolve } from "react-resolver";

// Assuming this _is_ from <Route> component matching `/users/ericclemmons`
@resolve("user", function(props) {
  return axios
    .get(`https://api.github.com/users/${props.params.user}`)
    .then((response) => response.data)
  ;
})
export default class Stargazer extends React.Component {

Or, if ES7 decorators aren't your bag:

class Stargazer extends React.Component {
  ...
}

export default resolve(Stargazer)("user", function(props) { ... });

3. Render on the Client

Again, if we're only rendering on the client, we can render like normal:

import React from "react";

Router.run(routes, location, (Root) => {
  React.render(<Root />, document.getElementById("app"));
});

The End. (Unless you want to see how to build a universal application)

4. Resolve on the Client

React Resolver handles bootstrapping server-rendered markup via Resolver.render:

import { Resolver } from "react-resolver";

Router.run(routes, location, (Root) => {
  // To preserver context, you have to pass a render function!
  Resolver.render(() => <Root />, document.getElementById("app"));
});

5. Resolve on the Server

The server will look very familiar to the client-side version. The difference being, Resolver.resolve will async render the application, fetch all data, & return a <Resolved /> component ready for React.render, as well as the data needed to bootstrap the client:

import { Resolver } from "react-resolver";

Router.create({ location, routes }).run((Handler, state) => {
  Resolver
    .resolve(() => <Handler {...state} />) // Pass a render function for context!
    .then(({ Resolved, data }) => {
      res.send(`
        <!DOCTYPE html>
        <html>
          <body>
            <div id="app">${React.render(<Resolved />)}</div>

            <script src="/client.min.js" async defer></script>
            <script>
              window.__REACT_RESOLVER_PAYLOAD__ = ${JSON.stringify(data)}
            </script>
          </body>
        </html>
      `)
    })
    .catch((error) => res.status(500).send(error)) // Just in case!
  ;
});

Enjoy writing universal apps with clarity around data requirements!

Development

If you'd like to contribute to this project, all you need to do is clone this project and run:

$ npm install
$ npm test

Authors

License

Collaboration

If you have questions or issues, please open an issue!

Keywords

FAQs

Package last updated on 11 Aug 2015

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc