Adding resolver to React-router

6k views Asked by At

In react-router, is there any way to pass a property from the Route-definition that can be picked up within the Router.run function? I want specific actions to fire for specific routes. Something like this perhaps:

<Route handler={someComponent} resolve={someAction} />

In Router.Run i want to execute that given action defined in resolve. Is there any way of doing that?

The reason for doing this is to make sure that each route can instantiate service-calls (from a defined action) to make sure that the stores have the data needed for that route. Doing it in the component is also a possibility, the problem we have now is that several components within the same route needs the same data, making it requesting data from the API several times, and also triggering rerendering for each result comming in from those calls.

1

There are 1 answers

3
Michelle Tilley On BEST ANSWER

You can do something like this in React Router by adding a static (using createClass) or a property on the component class (when using ES6 classes) and then executing them with React Router.

var Component1 = React.createClass({
  statics: fetchData: function(params) {
    return API.getData(params);
  },

  // ...
});

class Component2 extends React.Component {
  // ...
}

Component2.fetchData = (params) => API.getData(params);

Then, when you run your router, look for all matched routes that have a fetchData static method and call it. We'll assume here that fetchData (and thus API.getData) returns a Promise:

Router.run(routes, function(Root, state) {
  var data = {};

  var routesWithFetchData = state.routes.filter(function (route) {
    return route.handler.fetchData
  });

  var allFetchDataPromises = routesWithFetchData.map(function (route) {
    return route.handler.fetchData(state.params).then(function (routeData) {
      data[route.name] = routeData;
    });
  });

 Promise.all(allFetchDataPromises).then(function() {
    React.render(<Root data={data} />, container);
  });
});

(See this React Router example for more details.)

You can solve the "multiple components fetch the same data" problem by ensuring that the API module will catch requests for the same data and assign them the same promise. Pseudocode:

API = {
  getData: function(params) {
    if (requests[params]) {
      return requests[params];
    } else {
      request[params] = new Promise(function(resolve, reject) {
        // fetch data here
      });
    }
  }
};