0
votes

I'm working on a demo app using redux. I have counter and theme reducers combined, unfortunately the increment or decrement action calls the theme reducer instead of counter reducer. If I have only one reducer (not combined) both reducers work fine. Does both reducer share their state? It seems like increment action calls the theme reducer's default sate.

Here is my code.

2
When dispatching an action all reducers are called.HMR
How could I separate them?Peter Vatler
When the reducer does not do anything with this action then return state. Your theme reducer is returning state.name so any next action will break everything.HMR
I need that default state for init theme, should I use multiple stores with only one reducer inside them?Peter Vatler

2 Answers

0
votes

With redux, when you trigger any action, all reducers are called with that particular action and its upto each reducer to handle that action.

When the reducer does not need to handle an action you need to return the orignal state

That is why a default statement in reducer switch function is required

Now in themeReducer, you initialse the state to be a theme object, but then CHANGE_THEME action you update the state to just store the name which breaks its storage pattern

Also as a default you are returning the state.name property which means that the next time the reducer just has state equal to the current theme's name

The solution is to keep storing the required theme is state as an object and in default case return state

Now while using the theme in settings.js you can use theme.name

reducers/theme.js

const themeReducer = (state = themes[0], action) => {
  switch (action.type) {
    case "CHANGE_THEME":
      document.documentElement.style.setProperty(
        "--primary-color",
        themes[action.payload].colors.primary
      );
      document.documentElement.style.setProperty(
        "--secondary-color",
        themes[action.payload].colors.secondary
      );
      return themes[action.payload];

    default:
      document.documentElement.style.setProperty(
        "--primary-color",
        state.colors.primary
      );
      document.documentElement.style.setProperty(
        "--secondary-color",
        state.colors.secondary
      );
      return state;
  }
};

export default themeReducer;

Settings.js

function Settings() {
  const counter = useSelector(state => state.counter);
  const theme = useSelector(state => state.theme);

  return (
    <div>
      <h2>This is the Settings page</h2>
      <span>Counter: {counter}</span>
      <br />
      <span>Current theme: {theme.name}</span>
      <Color />
    </div>
  );
}

Working demo

0
votes

Give the action types separate names and it will work just fine!

See this answer for more discussion: Should Actions in Redux always be unique?

Also, you seem to have a bug in the theme reducer which might account for some unexplained behavior as well