Skip to content
This repository was archived by the owner on Oct 26, 2018. It is now read-only.
This repository was archived by the owner on Oct 26, 2018. It is now read-only.

State storage in router location vs. Redux store #288

@dandelany

Description

@dandelany

Hi all - thanks for all the great work lately on 4.x.x. Apologies for opening another "existential discussion" ticket but I wanted to ask a few questions about the react-router-redux state model. I'm working on my first Redux app after several projects in Reflux, so some of this may just be some misunderstanding of how Redux is supposed to work.

Namely I want to question the axiom that "You should not read the location state directly from the Redux store." I know that it's currently unsupported due to react-router's asynchronicity, but I guess I'm wondering if there's a way to make it work. My use case is something like this:

I have a "page" in my SPA that is an interactive chart with a bunch of settings (filters, time ranges, that kind of thing). I'd like to store them in app state because some of the settings may be used by other components on other pages. So I wire the thing up with an UPDATE_CHART_SETTINGS Redux action and a chartReducer that maps the settings into state.chart.settings and it all works like a charm.

The thing is, I know that in a few weeks, the boss will come tell me that "settings X, Y and Z are the most important, we need to save them in the query string so that people can share links and see the same thing." So, (if I understand the docs correctly,) at that point I will need to add a history.pushState somewhere, either in the component onChange callback or (preferably?) in my action, to push the relevant settings to the URL when they change - so far so good. But I will also need to change how this state gets propagated to my components - I have to change my chart container's mapStateToProps to use props instead of Redux state, and I also have to thread react-router's location prop down to it, since it's not a top level Route in this case. And I have to do this for any other components which access this setting.

This seems like a code smell to me - fundamentally, the settings are all still the same kind of app state, and it feels strange to have to handle them differently based on which ones are "saved" in the URL. I think I would be mostly happy if react-router-redux could provide me with a way to know when it was safe to use the state stored in state.routing.location (ie. when the component tree matched state) - maybe something like a boolean state.routing.transitioning that, when true [edit: oops, meant false], guaranteed they were in sync.

But to go a bit further - the above solution would still require moving the Single Source of Truth about some of the settings out of state.chart.settings and into state.routing.location.query - it would be even better if I could just leave them where they were! Again, "URL-savedness" shouldn't dictate where the setting state is stored, IMO. I think in my perfect world, I would be able to define two reducer-esque functions somewhere that looked something like:

const querySettingKeys = ['filters', 'range'];
const paramSettingKeys = ['id'];

export function mapLocationToState(location, state) {
  switch(location.pathname) {
    case "/chart":
      const settings = Object.assign({}, state.chart.settings, 
        _.pick(location.query, querySettingKeys),
        _.pick(location.params, paramSettingKeys)
      );

      return _.merge({}, state, {chart: {settings}});

    default: 
      return state;
  }
}

export function mapStateToLocation(state, location) {
  const query = _.pick(state.chart.settings, querySettingKeys);
  const params = _.pick(state.chart.settings, paramSettingKeys);

  return _.merge({}, location, {query, params});
}

...and then wire them up to react-router-redux to keep them in sync. Something along these lines seems to me like it would a good functional approach to passing state between location and store - and it would be easyish to unit test by ensuring that mapStateToLocation(mapLocationToState(someLocation)) === someLocation. It would be great to at least get some feedback to know if this falls into the category of A) hmm, interesting... B) trivially possible already somehow, or C) crazy ramblings of a naive Redux dev who has not yet learned the Way. :)

Thanks very much for your time!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions