0

I'm expanding the functionality of a local-only React app to hook into an API. Here is my code before the refactor. You'll see I'm setting initial state from a global window variable, INIT_STATE, which also includes some other root-level objects.

I'm focusing in on one of these root-level objects, called "projects".

For the projects reducer, I was normalizing (using normalizr) the state like such and combining reducers to get use reducers for the normalized entities:

window.PROJECTS_STATE = fromJS(normalize(window.INIT_STATE.projects, projectsSchema));

const result = (state = window.PROJECT_STATE.get('result'), action) => {
  switch (action.type) {
    default:
      return state;
  }
};

// In these reducers, currently, I'm getting init_state from window.PROJECTS_STATE
// i.e. window.PROJECT_STATE.entities.projects), which has been normalized above
const entities = combineReducers({
  projects,
  items,
  events,
});


// Here is where I'd like to handle an action to normalize and 
// overwrite the state of `projects` and all it's sub-reducers
export default () => combineReducers({
  entities,
  result,
});

In my refactor I've dispatched actions to fetch and receive API requests in my top level container. I can easily set my initial state of the other root-level objects from what used to be in INIT_STATE by handling the action GET_REQUEST_SUCCESS in those reducers to return that part of the response, but since projects is normalized and has nested sub-reducers, I'm unsure how to tackle setting this state with combineReducers.

So ultimately, I want to be able to combine reducers while also handling an action that can overwrite the state of all its sub-reducers. Is this possible or is there a better way to approach about this?

Many thanks.

aesterisk_
  • 329
  • 4
  • 15
  • What exactly is the problem? even if you have nested reducers the combine reducers should just pack all of the reducers, action should still be dispatched to all of them, regardless of sub nesting – Oscar Franco Feb 15 '19 at 22:38
  • @ospfranco The problem is that I don't want to handle the action at a per-reducer level. I need to normalize the data just for the projects part of the API response. I'd like to do that just once in an action in the projects reducer. If I didn't have to use combineReducers this would be simple, but I don't know how to make this higher level reducer take an action while also combining sub-reducers. – aesterisk_ Feb 16 '19 at 13:41

1 Answers1

0

From what I see what you want is to persist and re-hydrate some saved state into your reducers state, Redux persist was designed especifically for this purpose, you can set up a blacklist or a whitelist for each reducer you want to save the state for or not save the state for, this might help you accomplish what you want.

However if you still want to restore the state of an entire tree in one go, I'm afraid it might not be possible (as far as I know), it kinda goes against the functional nature of redux (no side-effects), modifying the state of all reducers from a high-level reducer is a big side-effect, combineReducers is nothing more than just a packing reducers in a bundle, but logically they all (should) remain decoupled.

That being said you could try to modify your action in a middleware before each reducer processes it, but there is no going around the fact that reducer -> catch action -> new state and that ALL reducers get ALL actions, that is kinda the whole problem redux tries to solve, going around it invalidates the point of the library.

Oscar Franco
  • 5,691
  • 5
  • 34
  • 56