Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React/redux, displaying multiple components, sharing same actions, but with different state

Tags:

reactjs

redux

Let's say I have a reusable container. It is a wizard with multiple pages.

The wizard state is driven by redux/actions. When an action is fired, I use a reducer to update my state.

What if I want to have multiple wizards duplicated, with it's own state?

I am thinking there must be a way to have actions handled by a certain dynamic reducer (that can be created/destroyed), and then have each individual wizard driven from these dynamic pieces of the store/state.

Is this recommended? Are the libraries out there that make this easier?

like image 279
Paul Knopf Avatar asked Mar 30 '16 08:03

Paul Knopf


1 Answers

Just partition your main state into as many wizard states as you need and send a wizard id along with each action so that your reducer knows which one to tackle.

As Array

{
  wizards: [
    { id: 'A', state: true },
    { id: 'B', state: false },
    { id: 'C', state: true }
  ]
}

You can write a wizard reducer which understands how to reduce a single wizard state.

function wizardReducer(wizard, action) {
  switch(action) {
    case 'TOGGLE':
      return {
        id: wizard.id,
        state: !wizard.state
      };
    default:
      return wizard;
  }
}

Then write a wizardsReducer which understands how to reduce a list of wizards.

function wizardsReducer(wizards, action) {
  return wizards.map(function(wizard) {
    if(action.id == wizard.id) {
      return wizardReducer(wizard, action);
    } else {
      return wizard;
    }
  });
}

Finally, use combineReducers to create a root reducer which delegates responsibility for the wizards property to this wizardsReducer.

combineReducers({
  wizards: wizardsReducer
});

As Object

If you're storing your wizards in an object instead, you'll have to construct your wizardsReducer slightly differently.

{
  wizards: {
    A: { id: 'A', state: true },
    B: { id: 'B', state: false },
    C: { id: 'C', state: true }
  }
}

It wouldn't make much sense to map over the states, when we can just select the state we need straight away.

function wizardsReducer(wizards, action) {
  if(!(action.id in wizards)) return wizards;

  const wizard = wizards[action.id];
  const updatedWizard = wizardReducer(wizard, action);

  return {
    ...wizards,
    [action.id]: updatedWizard
  };
}
like image 160
Dan Prince Avatar answered Oct 05 '22 10:10

Dan Prince