what is this difference between this flux action and this function call?
Asked Answered
R

2

14

I could a have a flux action like this:

{type: 'KILL', payload: {target: 'ogre'}}

But I am not seeing what the difference is between having a method on a class People (wrapping the store) like this,

People.kill('ogre') 

IF People is the only receiver of the action?

I see that the flux dispatcher gives me two advantages (possibly)

  1. The "kill" method can be broadcast to multiple unknown receivers (good!)
  2. The dispatcher gives me a handy place to log all action traffic (also good!)

These might be good things sure, but is there any other reasons that I am missing?

What I don't see is how putting the actions in the form of JSON objects, suddenly enforces or helps with "1-way" communication flow, which is what I read everywhere is the big advantage of having actions, and of flux.

Looks to me like I am still effectively sending a message back to the store, no matter how I perfume the pig. Sure the action is now going through a couple of layers of indirection (action creator, dispatcher) before it gets to the store, but unless I am missing something the component that sends that action for all practical purposes is updating whatever stores are listening for the kill message.

What I am missing here?

Again I know on Stack Overflow we can't ask too general a question, so I want to keep this very specific. The two snippets of code while having different syntax, appear to be semantically (except for the possibility of broadcasting to multiple stores) exactly the same.

And again if the only reason is that it enables broadcasting and enables a single point of flow for debug purposes, I am fine with that, but would like to know if there is some other thing about flux/the dispatcher I am missing?

Rafaelarafaelia answered 25/1, 2017 at 4:55 Comment(0)
C
9

The major features of the flux-style architecture are roughly the following:

  1. the store is the single source of truth for application state
  2. only actions can trigger mutation of the store's state
  3. store state should not be mutated directly, i.e. via assigning object values, but by creating new objects via cloning/destructuring instead

Like a diet, using this type of architecture really doesn't work if you slip and go back to the old ways intermittently.

Returning to your example. The benefit for using the action here is not broadcasting or logging aspects, but simply the fact that the People class should only be able to either consume data from a store and express its wishes to mutate the state of said store with actions. Imagine for example that Elves want to sing to the the ogre and thus are interested in knowing the said ogre is still alive. At the same time the People want to be polite and do not wish to kill the ogre while it is being serenaded. The benefits of the flux-style architecture are clear:

class People {
  kill(creature) {
    if (creatureStore.getSerenadedCreature() !== creature)
      store.dispatch({ type: 'KILL', payload: { target: creature } })
    return `The ${creature} is being serenaded by those damn elves, let's wait until they've finished.`
  }
}

class Elves {
  singTo(creature) {
    if (!creatureStore.getCreatures().includes(creature))
      return store.dispatch({ type: 'SING_TO', payload: { target: creature } })
    return `Oh no, the ${creature} has been killed... I guess there will be no serenading tonight..`
  }
}

If the class People were to wrap the store, you'd need the Elves class to wrap the same store as well, creating two places where the same state would be mutated in one way or the other. Now imagine if there were 10 other classes that need access to that store and want to change it: adding those new features is becoming a pain because all those classes are now at the mercy of the other classes mutating the state from underneath them, forcing you to handle tons of edge cases not possibly even related to the business logic of those classes.

With the flux style architecture, all those classes will only consume data from the creatureStore and dispatch actions based on that state. The store handles reconciling the different actions with the state so that all of its subscribers have the right data at the right times.

The benefits of this pattern may not be evident when you only have a couple of stores that are consumed by one or two entities each. When you have tens (or hundreds) of stores with tens (or hundreds) of components consuming data from several stores each, this architecture saves you time and money by making it easier to develop new features without breaking existing ones.

Hope this wall-o-text helped to clarify!

Counselor answered 27/1, 2017 at 20:20 Comment(0)
K
2

What I don't see is how putting the actions in the form of JSON objects, suddenly enforces or helps with "1-way" communication flow, which is what I read everywhere is the big advantage of having actions, and of flux. Looks to me like I am still effectively sending a message back to the store, no matter how I perfume the pig. Sure the action is now going through a couple of layers of indirection (action creator, dispatcher) before it gets to the store, but unless I am missing something the component that sends that action for all practical purposes is updating whatever stores are listening for the kill message. What I am missing here?

Facebook Flux took the idea from the event driven GUI systems. In there even if you move your mouse you get messages. This was called message loop then, and now we have actions dispatching.

Also, we have lists of subscribers inside stores.

And it is really the same principle in Redux where you have one store, while in Flux you may have multiple stores.

Now little mathematics. Having 2 components A and B you need to have just a few possible update chains A updates B and B update A, or self-update (non including in here the updates from outside of the app). This is the possible case.

enter image description here

With just three components we have much more possible chains.

enter image description here

And with even more components it gets complicated. So to suppress the exponential complexity of possible components interaction we have this Flux pattern which in nothing more than IDispatch, IObservable if you worked with these interfaces from some other programming languages. One would be for spitting the actions, and the other for entering the listener's chain that exists inside the store.

With this pattern, your React code will be organized in a different way than common React approach. You will not have to use React.Component state anymore. Instead, you will use the Store(s) that will hold the application state.

Your component can only show the desire to mutate the application state by dispatching the action. For instance: onClick may dispatch the action to increment the counter. The actions are objects with the property type: that is usually a string, and usually in upper case, but the action object may have many other props such as ID, value,...

Since the components are responsible for rendering based on the application state we need somehow to deliver them the application state. It may be via the props = store.getState() or we may use the context. But also check this.

Finally, it is even not forbidden that component uses the internal state (this.state) in case this has no impact on the application. You should recognize these cases.

Kauffmann answered 2/2, 2017 at 14:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.