Problem outline

Below is a standard way for dispatching error / success messages, at least that's what the tutorials recommend:

{ type: 'FETCH_POSTS_FAILURE', error: 'Oops' } { type: 'FETCH_POSTS_SUCCESS', success: 'yay', response: { ... } } { type: 'FETCH_POSTS', status: 'error', error: 'Oops' } { type: 'FETCH_POSTS', status: 'success', response: { ... } }

However, the problem I'm experiencing with this, is that these error / success messages will show inside EVERY component listening to the specific reducer that's handling these actions.

Example scenario:

Image you have a todo application which has three actions add, edit and delete however all three of those actions are performed from separate pages in terms of UI. And they're all handled by the same todo reducer.

Also all components that provide UI for triggering these actions are listening to this todo reducer via mapStateToProps to receive todo changes (not relevant in this example) and success & error messages:

function mapStateToProps(state) { return { success: state.todo.success, error: state.todo.error, }; } {!!this.props.success && <p>{this.props.success}</p>} {!!this.props.error && <p>{this.props.error}</p>}

Issue with above The problem is that there’s no way to distinguish between add todo errors, edit todo errors and delete todo errors.

So if add todo triggers an error this error will now also show up next to edit todo and delete todo, because all 3 actions are listening for the same: state.todo.error.

Below are the 2 solutions I came up with. Any feedback / critique as well as new suggestions would be more than welcome.

What I came up with so far

1: Global status reducer that handles errors / successes of each action

Setup a global status reducer that handles errors / successes of each action - keys on the reducer would consist of small specialised sub-reducers unique to each action, i.e.:

const status = combineReducers({ add_todo, // handles error/success for add_todo edit_todo, // handles error/success for edit_todo delete_todo, // handles error/success for delete_todo … update_bio, // handles error/success for update_bio etc... });

Then you can simply listen for these success / error messages in your components and render them as follows:

function mapStateToProps(state) { return { error: state.status.add_todo.error, success: state.status.add_todo.success }; } {!!this.props.error && <p>{this.props.error}</p>} {!!this.props.success && <p>{this.props.success}</p>}

etc...

function mapStateToProps(state) { return { error: state.status.edit_todo.error, success: state.status.edit_todo.success }; } {!!this.props.error && <p>{this.props.error}</p>} {!!this.props.success && <p>{this.props.success}</p>}

The downside of this is that it would force you to create a sub-reducer for each action that an application provides, which I'm not sure is a correct way of doing it?

2: Use locally unique error / success keys inside of each reducer that manages more than a single action

i.e. we could modify the todo reducer as follows:

ADD_TODO_FAILED: return {...state, error_add_todo: action.error } EDIT_TODO_FAILED: return {...state, error_edit_todo: action.error } DELETE_TODO_FAILED: return {...state, error_delete_todo: action.error }

Then you can simply listen for these success / error messages in your components and render them as follows:

function mapStateToProps(state) { return { error: state.todo.error_add_todo, success: state.todo.success_add_todo }; } {!!this.props.error && <p>{this.props.error}</p>} {!!this.props.success && <p>{this.props.success}</p>}

etc...

function mapStateToProps(state) { return { error: state.todo.error_edit_todo, success: state.todo.success_edit_todo }; } {!!this.props.error && <p>{this.props.error}</p>} {!!this.props.success && <p>{this.props.success}</p>}

The downside of this is would be that you would have to make sure that each error / success key inside of a given reducer is locally unique inside of that reducer.

And it would also make referring to keys inside of stateMapToProps more verbose as instead of saying state.todo.error your would have to refer to that error by using the specific name that you gave it.

Question

So my question is, based on all of the above, did I completely miss something out of the equation in my above observations, or were my observations correct in which case what is the standard way of achieving this desired outcome?

And are the 2 solutions I proposed legit or too naive for a real world application?

Thanks a lot!