18

I've got the fairly typical react-router app set up:

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

var routes = (
    <Route handler = { App }>
        < Route name = "Todo" path = "todo/:id" handler = {Todo}/>
        < DefaultRoute name = "Todos" handler = {Todos}/>
    </Route>
);

Router.run(routes, function(Handler) {
    React.render( < Handler /> , document.getElementById('content'));
});

My issue is that my Todos component has some search filters on it, and I want to persist those filters when I transition to a specific Todo and back. The obvious solution is to save those filter values on App's state, but I can't figure out an elegant way to allow Todos access to App's state.

Any hints?

Addendum: This app is using Reflux as well as react-router.

Matt Welch
  • 827
  • 2
  • 6
  • 12
  • 1
    I've been using filters as query params so they persist with the urls. Or are you wanting to cache the results? – BradByte Aug 20 '15 at 20:51

3 Answers3

6

I would the url to save the state filters and page numbers for listings.

One of react routers "Benefits of this Approach" is: URLs are your first thought, not an after-thought.

The url is a foundational part of the web, use it to your advantage don't try to avoid it.

By saving the filter state in the url you get back button support for free and you allow your users to keep that filtered state as a bookmark or link.

PetersenDidIt
  • 25,562
  • 3
  • 67
  • 72
  • 25
    What if your view is very complex and contains dozens of states, pre-fetched and rendered data? You can't put everything in URL. What about scroll position, also? – Slava Fomin II Apr 05 '17 at 23:08
4

You could do that by using something like Reflux to manage state across your entire application. It would act as your central store and central command library (actions)

var Reflux = require('reflux');

var actions = Reflux.createActions(
  ["getAction", "saveAction"]
);

var DataStore = Reflux.createStore({
  data: data,
  listenables: [actions],
  init: function() {
    this.trigger(this.data);
  },
  onGetAction: function() {
    // some ajax if you like
  },
  onSaveAction: function() {
    // more ajax
  },
  getInitialState: function() {
    return this.data;
  }
});

var App = React.createClass({
  mixins: [Reflux.connect(DataStore, 'datastore')],
  render: function () {
    var d = this.state.datastore;
    return (
    ...
Sina Khelil
  • 2,001
  • 1
  • 18
  • 27
  • Yeah, I was just editing my question to note that I'm already using Reflux. So you'd suggest using a Store to hold that information? That makes sense, though my use of Reflux so far has been to hook up an external API, so this use seems a little foreign to me. – Matt Welch Aug 20 '15 at 19:41
  • I just spent some time learning about reflux as well... not an expert to say the least, but I will admit that the egghead.io videos are pretty helpful, albeit a bit limited – Sina Khelil Aug 20 '15 at 19:47
1

You can use children or render instead of component in in order to HIDE instead of UNMOUNT the component once you navigate to another. Keep in mind that unmounting the component is the standard way of doing things in React and React-router since it keeps the DOM smaller and hence faster. e.g.:

    <Route path={/some-path} children={({ match }) => {
              return (
    <div style={{ display: match ? 'block' : 'none' }}>
        <YourComponentHere/>
    </div>
        )
      }}
    />              
T. Dayya
  • 690
  • 11
  • 12
  • I have tried your suggestions (children or render) but neither work for me. when going from component A to B and then back to A - A's state is initial because A was Unmounted then Mounted. Is it because I am using hashHistory maybe? (unfortunately required for Cordova apps) – Rhubarb65 Feb 25 '20 at 15:56
  • @Rhubarb65 do this for A not B! Hide it instead of unmounting it. – T. Dayya Feb 25 '20 at 20:53