redux-utilities / flux-standard-action

A human-friendly standard for Flux action objects.
MIT License
4.75k stars 142 forks source link

Error at the Action? #21

Open GantMan opened 8 years ago

GantMan commented 8 years ago

I'm coming to flux from a Rails/Ruby world (gasp!)

As I'm wrapping my head around Flux and standards (like FSA) I'm finding some questions pop up in my head, and whom better to answer than the FSA community/creator.

In FSA why is error state the job of the Action? That seems like we've overstepped, and for the wrong reasons. I don't think it's the action's job to choose something like validity (validity is a state).

An action is an abstract description of an operation to be performed. In databases you have transactions, in Android you have Intents, and in Rails you can attempt to modify a Model, but there's no guarantee that it will succeed, or yield a change. Should that be an error state? I think the reducer knows best.

Think of this: I can't buy -1 of something, but who's job should it be to tell me that? When I press the minus button on a cart, should my action check state to see if I'm at zero, and violate separation of concerns? Or should it just fire the action and my reducers take care of state (one managing my cart number at zero and another showing a red exclamation mark animation). Ok, not a great example, but I think it expresses the point. I feel errors shouldn't be part of actions, and I'm interested in hearing why otherwise.

EDIT

TL:DR; The error flag in FSA is bad

tomatau commented 8 years ago

I prefer to see actions more closely represent business logic, and so often have some definition of how to handle errors. Logic around errors, validity and defensive defaults etc, can be different on a use-case by use-case basis even within the same app -- so I prefer to have this described at the action level.

Also, when handling any side effects, such as transactions, these definitely do not belong in a reducer and so the error handling must happen in the action layer for these situations.

GantMan commented 8 years ago

Checking for errors at actions + async can allow for race conditions if you have sophisticated application. Business logic belongs in a controller-like component, and reducers are model-like.

I'll just have to disagree. Actions seem like a bad place to enforce protection of state in my opinion.

tomatau commented 8 years ago

How could actions introduce race conditions unless you fire off multiple actionCreators at the same time? Which is a pattern that is discouraged.

GantMan commented 8 years ago

I'm using redux-thunk to handle async actions inside my actionCreators. I could then attemptLogin which will have the actions REQUEST_LOGIN and RECEIVE_LOGIN respectively. Between the two, you could have the user press CANCEL_LOGIN.

Don't focus on the example, but async introduces variance of order, simply by definition.

tomatau commented 8 years ago

I'm in the habit of using flags in my reducers such as isPending so that the sequence of dispatched actions can be handled appropriately by the components responding to the said state changes. Action creators dispatching error actions can facilitate this process in sophisticated applications.

You're suggesting that components should initiate transactions, pass these results to the dispatch through an action creator and then the reducers all individually handle the response/error?

GantMan commented 8 years ago

close. The reducers set the state to error. They don't handle them. Basically, reducers are in charge of transforming state (as they should). Ultimately, I guess that's where we differ. We both agree that the problem needs to be handled (via flags/error or whichever we choose). The crux is where and when. And that depends on definition.

For me actions are signals that should not be stopped or stunted. If a button is pressed, let the associated action happen, because perhaps later or in some other aspect of your application you'll want to do something, like log user behavior or show a friendly message.

Reducers can receive error messages from actions, but ultimately they transform data. They should hold the rules of what error state should be. I hate to use the hackneyed DRY concept, but actions can possibly come from a multitude of places, and what qualifies state changes really only matters in one spot, the reducer.

tomatau commented 8 years ago

If the reducers are not handling the transaction fail event, what is?

GantMan commented 8 years ago

The "Dumb" components respond to the state change. Error state can cause some components to become non-editable, while others turn red, and even others display messages. When the props are mapped to state with connect, the components can then react accordingly to their own properties, powered by redux state.

tomatau commented 8 years ago

That didn't answer my question.

For example.. when you make an AJAX request... where do you put your onError or try/catch for this transaction?

GantMan commented 8 years ago

Sorry I missed what you meant and thank you for having this philosophical conversation with me :)

A response that is an error (not a 200) is passed on through the action as to a reducer. The action only cares a result has been returned (usually aptly named something like RECEIVED_X).

The reducer can then set state based on the payload. Now the reducer translates error state, like 401 can set state to "unauthorized". Which then prompts the correct behavior to deal with that state.

tomatau commented 8 years ago

OK so you still put the transaction in your actionCreator.

So when setting error messages based on say a connection error or invalid response from the server, you would still send an action that resembles a successful transaction -- The error information would still need to be dispatched in an action.

GantMan commented 8 years ago

Yes. I apologize for the confusion. My gripe is the error flag in FSA.

tomatau commented 8 years ago

Ahh! Yes you're not the only one! I'm not happy with that either and have been protesting for an API change around the error flag too :)

I think you should check existing issues before opening a new one https://github.com/acdlite/flux-standard-action/issues/17

GantMan commented 8 years ago

O good! I'm glad :+1:

and thank you again for your time in discussing redux with me :) It really helps me grok the concepts more deeply. I hope this thread helps others!