Yarden Ron
Yarden Ron

Reputation: 13

Redux with typescript - handle same action in different reducers

As far as I know, one of the advantages of redux is when an action dispatches, several reducers can respond to that action, each one of them doing their own logic. The problem comes when we have to combine redux with typescript.

If we take the example from the official site of redux, we can see it's following a certain pattern, where the actions and reducers are separated according to their role in the application.

chatReducer will only accept actions that belong to ChatActionTypes

export const SEND_MESSAGE = "SEND_MESSAGE";
export const DELETE_MESSAGE = "DELETE_MESSAGE";

interface SendMessageAction {
  type: typeof SEND_MESSAGE;
  payload: Message;
}

interface DeleteMessageAction {
  type: typeof DELETE_MESSAGE;
  meta: {
    timestamp: number;
  };
}

export type ChatActionTypes = SendMessageAction | DeleteMessageAction;
export function chatReducer(
  state = initialState,
  action: ChatActionTypes
): ChatState {
  switch (action.type) {
    case SEND_MESSAGE:
      return {
        messages: [...state.messages, action.payload]
      };
    case DELETE_MESSAGE:
      return {
        messages: state.messages.filter(
          message => message.timestamp !== action.meta.timestamp
        )
      };
    default:
      return state;
  }
}

systemReducer will only accept actions that belong to SystemActionTypes

export const UPDATE_SESSION = "UPDATE_SESSION";

interface UpdateSessionAction {
  type: typeof UPDATE_SESSION;
  payload: SystemState;
}

export type SystemActionTypes = UpdateSessionAction;
export function systemReducer(
  state = initialState,
  action: SystemActionTypes
): SystemState {
  switch (action.type) {
    case UPDATE_SESSION: {
      return {
        ...state,
        ...action.payload
      };
    }
    default:
      return state;
  }
}

Now the question is what we do when we want to use the same action in several reducers. Let's assume that in addition to the handling of "SEND_MESSAGE" in chatReducer, we would like also to respond to it in the systemReducer, what is the best practice/right way for doing that without breaking the pattern? (SEND_MESSAGE is indeed of type ChatActionTypes and systemReducer only accepts SystemActionTypes)

Upvotes: 1

Views: 567

Answers (1)

Richard Haddad
Richard Haddad

Reputation: 1004

reducer will only accept actions that belong to action

Nop ! Redux reducers receive all actions send to the store. Then it's up to you to handle some of them.

The example types its reducers action with ChatActionTypes and SystemActionTypes to ensure that you will handle only these types of action.

So in your case you have to enlarge your action type to handle others actions.

what is the best practice/right way for doing that without breaking the pattern ?

Well I like to use a type that group all my actions.

type StoreAction = ChatActionTypes | SystemActionTypes;

Then use it in all reducers.

export function chatReducer(
  state = initialState,
  action: StoreAction
): ChatState;

export function systemReducer(
  state = initialState,
  action: StoreAction
): SystemState;

Your reducers receive all actions, it's a fact that any typing will not change. So I find it consistent to allow my reducers to handle all of these actions.

At this point I think it's a question of preference, you may prefer to narrow the action type to the ones you want to use, or use the real type of the object.

Upvotes: 1

Related Questions