How to coordinate server error messages between Flux and React?
Asked Answered
M

2

11

I've been learning React and Flux over the past few months, and one thing I've not yet dealt with is displaying error messages to users. Specifically, error messages that occur as a result of an ajax http request within a flux action creator method.

A simple example is user sign in - if the sign in ajax request fails due to a bad password, the server responds with the failure. At that moment, within my flux action creator method, my only option is to dispatch an action containing the error information, right?

I can dispatch the error information and keep that error in a store. I'm not sure what the best way to tie certain errors to certain components is, though. Lets say my react component tree is rendering multiple error-aware components, but an error occurs during server-side user auth attempt and needs to be displayed on that sign in form.

Is there good pattern or convention for storing errors and knowing which component they're for? Is there a programmatic way of determining this, instead of passing in some identifier to every action creator function that identifies the component the action creator is called it, etc?

Masque answered 5/8, 2015 at 3:1 Comment(0)
M
10

Since you marked the question with Redux tag, I'm assuming you use Redux.
If so, this real-world example shows error handling.

There's a reducer that reacts to any action with error field:

// Updates error message to notify about the failed fetches.
function errorMessage(state = null, action) {
  const { type, error } = action;

  if (type === ActionTypes.RESET_ERROR_MESSAGE) {
    return null;
  } else if (error) {
    return action.error;
  }

  return state;
}

The custom API middleware puts any error message into error field on the action:

  return callApi(endpoint, schema).then(
    response => next(actionWith({
      response,
      type: successType
    })),
    error => next(actionWith({
      type: failureType,
      error: error.message || 'Something bad happened'
    }))
  );

Finally, the component reads the error message from Redux store:

function mapStateToProps(state) {
  return {
    errorMessage: state.errorMessage
  };
}

As you can see, this is not any different from how you'd handle displaying fetched data.

Maid answered 3/10, 2015 at 11:58 Comment(4)
Imagine a spreadsheet type application, in which each cell saves via ajax onblur. If the saving fails, the user should see an error message in the cell that failed to save. Now you potentially have an error message for each cell. Are you saving all those errors in the store itself? How are you mapping the errors to the cells? Thanks for any advice.Gumma
Assuming cells have some kind of IDs (which they need anyway to be used as key for efficient rendering), keep errorsByID: { id -> error } mapping in the store.Maid
Thanks for the reply. The issue I'm having with this solution is that my keys are not globally unique, but only unique among their siblings (which is allowed). Within a "row" the key is just the column index. This means every cell in the column would show the error. I could use "rowId + colIndex" for the "id" in errorsById, but even that breaks, eg, if I wanted to render two copies of the same grid on the page. So "identity" here becomes a nontrivial problem. Would passing a callback to the ajax function for onError which set the component state directly be terrible practice?Gumma
Nothing terrible about it, you don’t have to route anything through Flux. The question was about Flux specifically but this doesn’t mean you have to use it for this. :-)Maid
E
3

Your idea of keeping error info in a store is fine (probably an ErrorStore). But the store doesn't need to know the component interested in a particular error. Instead, the ErrorStore needs to emit a CHANGE event. When emitting that event, you can add an additional argument, namely the error type (which the store presumably gets from the action creator).

Now, any component can listen to the ErrorStore and check the error type (which it will get as an argument). Components can then know what kind of error was generated and decide whether they are interested in that or not.

Engineer answered 5/8, 2015 at 19:29 Comment(1)
That's kind of the route I was going to heads towards. I think it's the most straight forward in terms of a Flux-ish pattern.Masque

© 2022 - 2024 — McMap. All rights reserved.