Why should I use Actions in Flux?
Asked Answered
Z

2

7

An application that I develop was initially built with Flux.

However, over time the application became harder to maintain. There was a very large number of actions. And usually one action is only listened to in one place (store).

Actions make it possible to not write all event handler code in one place. So instead of this:

store.handleMyAction('ha')
another.handleMyAction('ha')
yetAnotherStore.handleMyAction('ha')

I can write:

actions.myAction('ha')

But I never use actions that way. I am almost sure, that this isn't an issue of my application.

Every time I call an action, I could have just called store.onSmthHappen instead of action.smthHappen.

Of course there are exceptions, when one action is processed in several places. But when that happens it feels like something went wrong.

How about if instead of calling actions I call methods directly from the store? Will my application not be so flexible? No! Occurs just rename (with rare exceptions). But at what cost! It becomes much harder to understand what is happening in the application with all these actions. Each time, when tracking the processing of complex action, I have to find in stores where they are processed. Then in these Stores I should find the logic that calls another action. Etcetera.

Now I come to my solution:

There are controllers that calls methods from stores directly. All logic to how handle action is in the Store. Also Stores calls to WebAPI (as usually one store relating to one WebAPI). If the event should be processed in several Stores (usually sequentially), then the controller handles this by orchestrating promises returned from stores. Some of sequentials (common used) in private methods of itself. And method of controllers can use them as simple part of handling. So I will never be duplicating code.

Controller methods do not return anything (one-way flow).

In fact the controller does not contain the logic of how to process the data. It's only points where, and in what sequence.

You can see almost the complete picture of the data processing in the Store. There is no logic in stores about how to interact with another stores (with flux it's like a many-to-many relation but just through actions). Now the store is a highly cohesive module that is responsible only for the logic of domain model (collection).

The main (in my opinion) advantages of flux are still here.

As a result, there are Stores, which are the only true source of the data. Components can subscribe to the Stores. And the components calls the same methods as before, but instead of actions uses controller. Interaction with React did not change at all.

Also, event processing becomes much obvious. Now I can just look at the handler in the controller and all becomes clear, and it's much easier to debug.

The question is:

Why were actions created in flux? And what are their advantages that I have missed?

Zanezaneski answered 28/11, 2014 at 14:31 Comment(0)
P
4

Actions where implemented to capture a certain interaction on the view or from the server which can then be dispatched to as many different stores as you like. The developers explained this with the example of the facebookchat. There is a messageStore and a threadstore. When the action eg. messagePost was emitted it got dispatched into both stores doing different work to update their attributes. Threadstore increased the number of unread messages and messageStore added the new message to its messagearray.

So its basicly channeling one action to perform datachanges in more than one store.

Pursuant answered 1/12, 2014 at 13:57 Comment(14)
It's possible to mark new messages as unread. And then count in thread store, how many messages is marked as unread.Zanezaneski
I think you dont get my point: 1 action gets dispatched and updates 2 stores. Its up to you as software architect to make this fit to your usecasePursuant
Facebook solution is better perhaps. But situations like this is more exception than rule usually. So, should I use architecture app based on exception? And create so many Actions used just on few cases? Occam would be unhappy.Zanezaneski
Well basicly by using actions you ensure a concentration of application logic. If you wouldnt implement the actions getting dispatched you would have to call your methods of your stores directly which raises your error potential. this is due to the fact that you can perform action A in controller 1 and 2.Pursuant
And to come back to your retorical question: "So, should I use architecture app based on exception?" You should use app architecture based on usecasePursuant
Or I can use smth like controller, that dispathes event not as observable, but in imperative way (so not stores subscribed to dispather, but dispather calls stores methods). Imperative code is better over Event-based when there isn't dynamically subscibed\unsubscribed listeners, and there isn't more than 2-3 listeners. Maybe this isn't true. But that is my question about. If I'm wrong, where and why?Zanezaneski
I think the point is to prevent bidirectional dataflow in general. This is done to keep the code maintainable. Example: Flux: Error accures - you check the action that is called, look where it is dispatched and check the logic in your stores the action "calls". Non-Flux: You search for the error not having a clear Idea where to start -> Events get triggered everywhere and methods get called in components without any concentration <ou simply lose the overview. Flux helps you with this especcialy in big projectsPursuant
Why Flux is better than non-flux is clear. But why flux is better than flux-without-actions? With dispather-controller it's much easer to handle errorsZanezaneski
what do you mean by dispatcher controller?Pursuant
Just described message above. "smth like controller, that dispathes event not as observable, but in imperative way (so not stores subscribed to dispather, but dispather calls stores methods)" And in question. About controllerZanezaneski
Ok to be honest I dont know a really good answer to that. I think the reason is to keep your stuff more modular and flexible(also considering the order of execution which may differ in usecases), but which is only neccessary in bigger projects. I think going with this method just gives you a better way to scale your app as it grows and only if it grows... but I think there might be alot more oppinions on this that should be involved in this discussionPursuant
The main difference I see is that a 'dispatcher calls store methods' approach requires that all the information of which stores should be invoked and how they should change in response to each event is collected into the dispatcher. Actions enable this information to be distributed throughout the stores so that each store just needs to know about itself and its dependencies rather than the dispatcher needing to know about all of the stores and their dependencies.Ithaca
"Occam would be unhappy" - perfectly put!Ssw
It is very much the question if a separate thread store and message store are needed, since they seem to have the same data. Unread messages can just as well be calculated by the message store. I too would like to see a real use case for different stores with orthogonal domains being interested in the same action.Severin
S
2

I had the same questions and thought process as you, and now I started using Flummox which makes it cleaner to have the Flux architecture.

I define my Actions in the same file where I define my Store, and that's close enough. I can still subscribe to the dispatcher to log events so I can see all actions being called, and I have the option to create multi-store Actions if needed.

It comes with a nice FluxComponent that lets you wrap all store-related code in a single place so its children are stateless components that get updated on store changes, like

  <FluxComponent connectToStores={['storeA', 'storeB']}>
    <InnerComponent />
  </FluxComponent>

Keeping the Flux architecture (it uses Facebook's Flux behind the scenes) will hopefully make it easy to use other technologies like GraphQL.

Severin answered 6/6, 2015 at 16:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.