Access component context inside ReactRouter's willTransitionTo and willTransitionFrom

1k Views Asked by At

I have a requirement to fetch data from a server everytime a page is rendered.

Usually this (ajax) request should be performed inside componentDidMount, but with ReactRouter, componentDidMount is not fired when a url has changed.

This is my attempt so far:

// App.js
var App = React.createClass({
  render: function() {
    return (
      <RouteHandler />
    );
  }

  var routes = (
    <Route handler={App} path="/" >
      ...
      <Route handler={PageA} name="PageA" path="/pagea" />
      ...
    </Route>
  );

  Router.run(routes, Router.HashLocation, function(Handler) {
    React.render(<Handler/>, document.body);
  });
});

// PageA.js
var PageA = React.createClass({
  statics: {
    willTransitionTo: function (transition, params, query, callback) {
      console.log("willTransitionTo PageA");
      this.handleGet(callback);
    }

    , willTransitionFrom: function (transition, component) {
      console.log("willTransitionFrom PageA");
    }
  }

  , handleGet(callback) { ... }

  ...
}

I would like to intercept an event 'page will appear' and willTransitionTo (and willTransitionFrom) seems to do the job as expected. However, the problem is I can't access PageA.handleGet inside that method. I would appreciate if you can guide me to a right path for achieving this task as I might misunderstand some important concepts of using a router.

P.S. I didn't use Flux (yet).

1

There are 1 best solutions below

0
On

I found a workaround at here where fetched data is passed down, as props, to a target component (PageA) by using a wrapper. Instead of managing ajax requests in the target component's componentDidMount, I have to do it in the wrapper component's componentDidMount. This way, App.js can become very large if there are many pages dealing with pre-loading requests.

// App.js
var PageAWrapper = React.createClass({

  getInitialState: function() {
    return {
      data: []
    };
  }

  , handleGet: function() {
      var promise = $.ajax({...});
      promise.done(function(data) {
        this.setState({data: data});
      }.bind(this));
  }  

  , componentDidMount: function() {
    this.handleGet();
  }

  , render: function () {
    return (
      <PageA data={this.state.data} />
    );
  }
});

...
var routes = (
  <Route handler={App} path="/" >
    ...
    <Route handler={PageAWrapper} name="PageA" path="/pagea" />
    ...
  </Route>
);

EDIT

Because data is mutable inside PageA, but I am forced to pass it as props. Therefore, I also have to modify PageA slightly.

var PageA = React.createClass({
  getInitialState: function() {
    return {
      data: []
    };
  }

  , componentWillReceiveProps: function(nextProps) {
    this.setState({data: nextProps.data})
  }

  , render: function() {
    ... use this.state.data to render ...
  }
});