Incrementing variable in action creator - javascript

I was recently watching Dan Abramov redux series and one episode got me really curios. In this episode - Redux: Extracting Action Creators, timecode: 00:32~1:32 he's making action creator as a separate function (like it would normally look in the typical redux application) because:
... However, what if another component wants to dispatch the add todo
action? It would need to have the access to next todo ID somehow
But is that actually making any sense? In that particular example, nextTodoId variable (which is always incrementing) is available to all components inside that jsbin even if we don't extract action creator into a function.
Even if we'll imagine that it will be in a separate file (action creator), on each import that variable will be equal to the initial value (0) which breaks it's uniqueness concept.
So, what does he meant by that? How is that approach (of making action creators as a separate functions) will guarantee us the acccess to that next todo id variable?

You're focusing on the wrong aspect. It's a fair enough point that this is a terrible way to store "current ID", but that isn't the purpose of the refactor he is showing.
The real purpose is that Components should be as agnostic about their context as possible. A Component trying to "addTodo" really shouldn't be concerned with "what is the current max todo ID?".
In contrast, the actionCreator is concerned with this aspect. It takes in data from the components and is then responsible for translating it to a dispatchable call that has real value.

Related

Passing values between components: Pass References vs Subjects

tl;dr: Why not pass variables by reference between components to have them work on the same data instead of using e.g. BehaviorSubjects?
I'm writing a sort of diary application in Angular 8. I have two components (Navbar and Dashboard) and a service (EntryService).
Navbar lists the entries, Dashboard provides the textarea, EntryService glues them together and communicates with the database.
While debugging the application I stumbled upon a way to communicate between the service and a component that i haven't thought of before.
By accident I passed a variable (entry: Entry) from the Dashboard by reference to the EntryService. The service saved to the database getting a unique ID back and saving this ID into the entry variable. This change immediately reflected to the Dashboard because of the 'passing by reference'.
Until now I was using Subjects to update the components on changes, but passing references around seems to be much simpler, because I want to work on the same data on both components and the service.
I've studied Angular for a while now and not read about this approach, so I'm wondering if it is a bad idea or design and if yes why?
Thanks for your answers!
Passing by reference can be handy. But as a general approach to keep the application components in sync it has some draw backs. With Subjects you can easily investigate in which places of the application the value of the Subject will be changed by checking where the Subject.next() function is being called. When you pass your object by reference to a hundred components/services it will be much more difficult to find out, which of them modify the object and more importantly when, becaue often you want to trigger other changes afterwards. When you subscribe to Subjects, you get notifications about changes and can react to them. Subjects and Subscribers are an example for an Observer/Observable pattern, it allows you to decouple your application logic. And they are much more flexible, for example you can have a Subject which can return the last x number of changes or you can debounce the changes when you track user input, you can apply filters to them etc.

Redux - how is state passed to reducers?

I'm just wrapping my head around Redux and I just wanted to run a question by on how state is passed to reducers:
I understand that the structure of state is dictated by the combineReducers() function and that the keys that you define within this function will become the various properties of state.
Am I correct in saying that only the subset of state that is associated with a particular reducer is passed to the reducer? Or is the entire state object passed?
Having lots of 'ahahhh' moments with Redux...!
combineReducers takes a number of reducers as parameters and returns a reducer. The particular reducer created by combineReducers only passes the part of the state assigned to a particular reducer. This way each reducer is completely in charge of its own part of the state and nothing more.
But you can write your own kind of combineReducers that could work differently. This is just to say that there is nothing special about combineReducers.
A reducer is just a function that takes a state and an action and returns the state with the action applied in some way. Or not, at its discretion.
For instance, in Redux it is common for separate branches of the state to handle the same (set of) actions but handle them in different ways that make sense for that part of the state. Each action is passed to all sub-reducers by combineReducers, giving each branch's reducers a chance to either do something, or nothing.
So in most common usage, a reducer is solely responsible for a slice of the state and sub-reducers, such as those passed to combineReducers, or reducers called by your own reducers, are solely responsible for their sub-state/branch.
But your own reducers may call a sub-reducer and pass it anything you like, such as the same state that was already passed to some other reducer, or even some data it created without it ever having been available in the global state.
These things are not common, but if you see a need, and feel confident to go forward with it, you are encouraged to use what you believe works best. Great power comes with great responsibility.
combineReducers is just a helper function for a common use case. It's probably cleanest to make a single reducer responsible for a particular branch of the state, but there may be situations where you find it beneficial to do things differently. A single reducer can manage a complex object with nesting without calling any other reducer, but a common pattern is to make smaller reducers to handle parts, if the parent is getting unwieldy.
The main point is to realize that a reducer is always a pure function that takes state and an action and returns a state. How you make this happen is entirely up to you. Most developers choose to follow common patterns seen in other's code, such as Dan's Redux examples or the videos he has on egghead.io.
Treading on the beaten path is often a good way to start out because it has already been vetted.
By the same token, however, it is always important to know why something is done. Developers sometimes make things more complex than it needs to be because of following an example that either was meant for something else or wasn't thought through very well to begin with.
Also read this article by Dan.

Flux: should not-top-level views be "dump" (do not fetch data from stores)

Maybe at official flux website I saw a video were mentor said something like:
Only top-level React views should know about stores. All not top level
views should be dump and receive all information as properties.
Question: Is that right? Your argumentation, please
BUT, suppose you have some small React view Button.react that's reused on multiple pages. And suppose Button.react must know about some store data. If we won't fetch all data directly from the Button.react, we get a duplication of code at each top-level component which reuse Button.react. Is that ok for you?
I hope I am understanding your question.
One of the characteristics of React is its one-way data flow. Each component can be used by another component, just like one function can call another function. Just like a function, a React component should typically be able to get all the info it needs to do work (render itself) from the arguments passed into it. This is the function of props in React. When using Flux, sometimes the React Components, which are typically near the top of the view hierarchy, that actually fetch the data from the stores to pass down thru the application are called Controller-Views.
It is not an enforceable rule that every component doesn't become a Controller-View, getting its own state directly from a store, but it is a general practice for good reason. consider the two functions:
function renderToggleButton( isSelected ){
//... render the button
}
vs
function renderToggleButton(){
var isSelected = StateStore.getButtonSelectedState( id );
//... render the button
}
I think you will agree that the second function is more complicated and difficult to test. It has to know from where it is getting it's initial conditions. It also has to know how to identify itself in the context of the application. These are two things the function should not have to know.
Now imagine an application full of functions like this. If one function is misbehaving, it becomes very difficult to trace its inputs; to test it under controlled conditions. I hope that clarifies the guidance given for passing data thru the application as props.

Flux calling actions with arguments managed in store

Say I have an action someAction(params) that takes params which is managed in a store paramsStore:
paramsStore.listen(function(params) {
someAction(params)
})
It seems that I can't just call this in my view because apparently this goes against the Flux way of doing things (actions shouldn't be called within store listeners).
The reason I have someAction inside the store listener, is because I want it to be called every time the paramsStore is modified. How can I achieved this without resorting to the 'unpattern' of calling actions within stores listener?
The right "flux way" of doing it would be to call the someAction(params) wherever information is dispatched to paramsStore.
Understanding what someAction does will give more clarity. Does it really need to be an action? If you're just doing some manipulation in the store data, you could have it as a local method in the paramStore.
While I am new to flux as well I could offer a suggestion. State that is needed to determine the outcome of an action that is held by Store A could be attached to a get method. This state can be retrieved by a View with a getter. When the action is called this state can be sent as a parameter. If something needs to be async it can now be done here (ajax call or something else) based on what the state is. Either the result of this or a promise object can then be used to trigger an action which is passed to the dispatcher. The dispatcher sends the result or promise to the store. The store then updates its state and the process repeats as necessary (when initial action is triggered).
I think a little more detail of what exactly you need would help actually. I do believe listening for for an action and triggering another action inside the store doesn't coincide with flux. I do think there is likely a way to accomplish the actual result you want using flux but without more detail this is the best I could come up with. Also, in reality you can implement anything you want. Flux is just a model and by extension a self imposed constraint to help with structure.
If you are using Flux as is, you could refer to the original image of the whole architecture at https://github.com/facebook/flux.
As you can see not only views could create actions. There are also Web API Utils which could create ones. Generally speaking not only API utils can do this. It's totally okey to create actions in order to start some behaviour according to outside world, some services or something else.
But in your case you are trying to create an action on some store update listener. As far as I can understand this would result in some changes in one or few other stores. In this case you probably don't need to create an action in the listener, but rather create some relations between your stores with waitFor API. Here is a link with detailed information: http://facebook.github.io/flux/docs/todo-list.html#adding-dependency-management-to-the-dispatcher.

What if two Flux stores have to depend on each other

One of the goals of Flux is to make the app more predictable by reducing crazy tangled dependencies. Using the Dispatcher you can define a strict order in which the Stores are updated. That creates a nice tree dependency hierarchy. That's the theory. Consider following situation:
I have a game. The store sitting at the top of the hierarchy is StateStore that holds only the current game state, i. e. playing, paused, over. It is updated via actions like PAUSE or RESUME. All other stores depend on this one. So when a store handles some kind of update action (i. e. MOVE_LEFT), it first checks the StateStore and if the game is paused or over, it ignores the action.
Now let's say that there is an action that would cause game over. It updates some store and the store decides that the game shouldn't continue ("the game character moves left and falls into a trap"). So the state in the StateStore should change to over. How do I do that?
Theoretically, it should go like this:
The given store is updated first and reaches the point of game over
The StateStore is updated afterwards (it waitsFor the other store), checks the other store and switches the state to over.
Unfortunately, the other store needs to access the StateStore as well to check the current game state to see if it should be updated at all (i. e. the game is not paused). They clearly depend on each other.
Possible solutions:
Merge such stores into one store. That would probably cause my whole app to collapse into a single store which brings up the question whether Flux in this case is a good idea.
Distinguish update order and read-only dependencies. All stores would be updated in a strict order, however they could read from each other arbitrarily. The StateStore would therefore for every action check all existing stores and if any of them indicated game over, it would change the state to over, effectively preventing all other stores from updating.
What do you think?
In Flux stores should be as independent from each other as possible and should not read from each other. The only way to change their state is through actions.
In your case, if some store decides that the game is over — you should update a StateStore from the ActionCreator. You can do it by calling a HaltGameActionCreator from the store or by dispatching a HALT_GAME action from ActionCreator that triggered the store change in the first place.
For those having the same issue, you can read here about the actual application I had this problem with and how I approached it. Long story short, I allowed all the stores to arbitrarily read from each other (the suggested solution no. 2).
Note that ES6 modules allow circular dependencies which simplifies the implementation.
Nevertheless, looking back I'm not sure if it was a right decision. If a piece of business logic inherently contains a circular dependency, we should not try to apply a solution that doesn't really support it just because somebody says so. Flux is only one pattern, there are many other ways how to structure the code. So perhaps I would recommend collapsing the whole logic into a single store and use one of the other ways to implement the store itself (e.g. standard OOP techniques).
I would also consider using redux with reselect instead of Flux. The problem with the original example is with the StateStore that depends on two different inputs. It can be changed either by the user explicitly pausing/resuming the game, or by the game situation reaching game over. The advantage of this approach is that you need to check only one store to get the current game state.
With redux/reselect, you'd have one reducer handling pause/resume actions and another reducer handling the game situation. Then you'd have a selector combining these two pieces of information into the final game state. Most of the business logic would be moved from the stores to action creators, i.e., in the moveLeft() action creator, you'd use this selector to check the game state and only then you'd dispatch MOVE_LEFT action.
Note that this is just a rough idea and I don't know if it's viable.

Categories

Resources