I'm familiarising myself with both Flux architecture, and Reflux - the simpler version, without a dispatcher - for use with ReactJS.
In full Flux, it sounds like actions have (or at least, can be made to have) a definite and non-trivial purpose: they can be used to update external services (eg. save data back to the server via an API), as described in this question: Should flux stores, or actions (or both) touch external services?
However, in Reflux, the actions are definitely just dumb message parsers. So my question is, what purpose do they serve? Why have them at all? What bad things would happen if your Views/Components just called methods on your store directly?
I'm about to convert my little app from Flux to Reflux, and it looks like I'll be moving all the logic currently in my actions over to the store. It seems to me like the actions in Reflux do nothing other than act as a useless middleman between the component and the store. What am I missing?
Besides the ability to listen for an action in any number of stores as pointed out in the OP comments:
Reflux actions can also touch APIs and such, by placing it in the preEmit action hook for example. Typically you'd create an async action, add some async stuff in the preEmit hook, and then call the "completed" or "failed" sub-actions when the async work is done (or has failed). You can also do sync work in the preEmit hook of course. Logging comes to mind.
It's also fully possible to listen to an action in a store and perform the async work in the store, then call .completed or .failed from there, but I think the consensus that has formed is that stores shouldn't do that work, stores should just react to changing data, not perform business logic.
Async actions also work as promises. Of course you could implement your stores to do that as well, but I'd argue that that's a lot of responsibilities for a data store.
Related
I just recently got introduced to Redux and decided to learn how to implement it. At the moment I'm refactoring some of my previous studying-projects and implementing the global state logic provided by the tool.
The thing is, I've recently stumbled upon the thunk middleware for async actions and got curious about something that's probably a simple concept misunderstanding but that I just can't get over.
So, why would I dispatch an async action? I just can't see the benefits of doing that way instead of waiting for the execution of whatever I'm doing and just then dispatch the action carrying the data I want.
Using a simple fetch call as an example, why would I not do the following:
->await fetch data
->dispatch fetched data
And instead do this:
->dispatch action
->await dispatch action
There's probably some use cases that I don't know of because for me, a beginner, sounds like extra code for something that maybe didn't require it? Idk.
Could someone help me? =)
Yep, as you found, that's Dan Abramov's original explanation of why something like the thunk middleware exists.
I recently wrote a new Redux docs page on Writing Logic with Thunks, which goes into more detail on the purpose behind thunks and how to use them correctly. I'll quote from the "Why Use Thunks?" section:
Thunks allow us to write additional Redux-related logic separate from a UI layer. This logic can include side effects, such as async requests or generating random values, as well as logic that requires dispatching multiple actions or access to the Redux store state.
Redux reducers must not contain side effects, but real applications require logic that has side effects. Some of that may live inside components, but some may need to live outside the UI layer. Thunks (and other Redux middleware) give us a place to put those side effects.
It's common to have logic directly in components, such as making an async request in a click handler or a useEffect hook and then processing the results. However, it's often necessary to move as much of that logic as possible outside the UI layer. This may be done to improve testability of the logic, to keep the UI layer as thin and "presentational" as possible, or to improve code reuse and sharing.
In a sense, a thunk is a loophole where you can write any code that needs to interact with the Redux store, ahead of time, without needing to know which Redux store will be used. This keeps the logic from being bound to any specific Redux store instance and keeps it reusable.
The Redux FAQ entry on "why do we use middleware for side effects?" links to additional information on this topic.
I would like to understand when it is appropriate to use a redux middleware over a redux-observable epic (and vice versa).
From the redux middleware documentation
It provides a third-party extension point between dispatching an action, and the moment it reaches the reducer. People use Redux middleware for logging, crash reporting, talking to an asynchronous API, routing, and more.
From the redux-observable documentation
While you'll most commonly produce actions out in response to some action you received in, that's not actually a requirement! Once you're inside your Epic, use any Observable patterns you desire as long as anything output from the final, returned stream, is an action.
My understanding is that an action in a redux middleware may or may not hit a reducer and if it does, it may or may not result in a change of state. In an epic you can produce a new action which may or may not hit a reducer or result in a change of state.
It looks like both can be used to enable side effects so the difference between the two is becoming a bit blurry to me.
Question: Is the FRP foundation the only thing that sets them apart or are there specific events in the lifecycle of an application that are better dealt with a classic middleware or an epic?
"Middleware" are a general type of thing that can be used to customize a Redux store. redux-observable is a specific Redux middleware, which lets you use RxJS logic to interact with dispatched actions.
We use Redux in large parts of our React application. One area where we struggle with is the context menu. Up to now it worked like this:
onRightClick -> createItems -> openMenu -> onItemClick: invoke callback and close menu
So we had a callback in each item when it is clicked. With Redux, that no longer works, because:
dispatch(actionCreator_openContextMenu(items))
... performs a store update. The Redux action returned by the action creator cannot have callbacks in it, because they are not serializable/jsonizable.
We furthermore need to perform asynchronous operations (i.e. server roundtrips) in many context menu click actions, so the click actions are not plain store updates.
The question is: how does this align with the Redux pattern and its constraints? How would one do this with Redux?
To clarify: this question is not about the UI side in react, it's about redux.
I actually wrote an article that covers this exact question: Creating Reusable Generic Modals in React and Redux. The approach I described in that article can be summarized as having the code that requests the dialog include a pre-made action object that gets passed to the dialog component as a prop, and the dialog can then dispatch that action (possibly with additional info attached) when it's closed.
A couple other options:
Have the dialog dispatch some "signal" action when it closes, and use sagas or observables to execute the additional async logic in response
There's an interesting-looking library called redux-promising-modals. I haven't used it yet myself, but it appears to have a prebuilt middleware and reducer for tracking a lost of open modals. The middleware returns a promise whenever you dispatch PUSH_MODAL_WINDOW, and will resolve the promise when you dispatch the corresponding POP_MODAL_WINDOW.
I think what you are looking for is a redux middleware that could handle async side effects. There are dozens of libraries out there that can help with this, but I would suggest your team looks into some of the following libraries that have great communities and are well documented:
Redux-Saga https://github.com/redux-saga/redux-saga (easy to understand and test)
Redux-Thunk https://github.com/gaearon/redux-thunk (extremely easy to understand, hard to test)
Redux-Observable https://redux-observable.js.org/ (you would need some previous knowledge on reactive programming, easier to test than redux-thunk)
Where ajax calls should be executed when using Redux with Angular 2?
I see two possibilities, first of that Service classes handles ajax call and other asynchronous operations and delegates the resulting Observable result for store to dispatch. This means that store is just responsible to store the byte state of an application, and Actions are mere carriers to transfer the bytes to store, without executing any logic, validation etc. This was my first impression Redux - Just create a new state based of an instruction and a payload, which is a result of an logical operation executed outside of Redux domain.
However, as I continued reading advanced chapters of Redux official documentation (Async actions and middleware), I got impressions that dispatching actions actually could execute logic, and in point of fact ALL program logic SHOULD be executed as a result of dispatching an action.
Now I'm very confused how the Reducers, Actions and store is intended to use, and what is their relation to events, local service calls, web API calls, routing etc.
You can definitely put business logic in your action creators. As I understand it, you want to keep your reducers as pure as possible with no side effects and limited logic.
Good Links:
this issue for more on how actions and reducers work together
this section of the Redux docs for more on API calls and asynchronous Redux
I understand that this image has been the ultimate guide of most, if not all, Flux programmers. Having this flow in mind, I have a few questions:
Is it correct/highly advisable to have all of my $.ajax calls inside my Web API Utils?
Callbacks call the action creators, passing the data in the process
If I want my Store to make an AJAX call, I do have to call the Action Creator first, right? Is it fundamentally incorrect to call a function in Web API Utils directly from Store?
Is there like a virtual one-sided arrow connecting from Store to Action Creators?
I have a lot of operations that do not go through views
What are the Callbacks between Dispatcher and Store?
What's the Web API here? Is this where you'd apply a RESTful API? Is there an example of this somewhere?
Is it okay to have a logic involved (to know which Action to dispatch) in one of my Action Creators? Basically, this action receives the response from my AJAX call. This is a snippet:
var TransportActions = {
receiveProxyMessage: function (message, status, xhr) {
switch (message) {
case ProxyResponses.AUTHORIZED:
AppDispatcher.dispatch({
type: ActionTypes.LOGIN_SUCCESS,
reply: m
});
break;
case ProxyResponses.UNAUTHORIZED:
AppDispatcher.dispatch({
type: ActionTypes.LOGIN_FAIL,
reply: m
});
break;
...
}
}
}
I've seen a lot of different answers online, but I am still not sure how I would incorporate all of them in my application. TYIA!
Is it correct/highly advisable to have all of my $.ajax calls inside my Web API Utils? Callbacks call the action creators, passing the data in the process.
Yes, you should put all your request into a single entity, i.e. the Web API Utils. They should dispatch the responses so any store can choose to act on them.
I wrote a blogpost a while ago showing one way on how to handle requests http://www.code-experience.com/async-requests-with-react-js-and-flux-revisited/
If I want my Store to make an AJAX call, I do have to call the Action Creator first, right? Is it fundamentally incorrect to call a function in Web API Utils directly from Store?
This is a good question, and as far as I have seen it, everybody does it a little different. Flux (from Facebook) does not provide a full answer.
There are generally two approaches you could take here:
You can make the argument that a Store should not "ask" for any data, but simply digest actions and notify the view. This means that you have to fire "fetch" actions within the components if a store are empty. This means that you will have to check on every data-listening view if it has to fetch data. This can lead to code duplication, if multiple views listen to the same Store.
The Stores are "smart" in the sense that if they get asked for data, they check if they actually have state to deliver. If they do not, they tell the API Utils to fetch data and return a pending state to the views.
Please note that this "tell the API to fetch data" is NOT a callback based operation, but a "fire and forget" one. The API will dispatch actions once the request returns.
I prefer option 2 to option 1, and I've heard Bill Fisher from the Facebook team say that they do it like this as well. (see comments somewhere in the blogpost above)
so No it is not fundamentally wrong to call the Api directly from the Store in my opinion.
Is there like a virtual one-sided arrow connecting from Store to Action Creators?
Depending on your Flux implementation there might very well be.
What are the Callbacks between Dispatcher and Store?
They are the only functions that can actually change the state in a store! each Store registers a callback with the Dispatcher. All the callbacks get invoked whenever a action is dispatched. Each callback decides if it has to mutate the store given the action type. Some Flux libraries try to hide this implementation detail from you.
What's the Web API here? Is this where you'd apply a RESTful API? Is there an example of this somewhere?
I think in the picture the Web API rectangle represents the actual server, the API Utils are the ones that make calls to the server (i.e. $.ajax or superagent). It ist most likely a RESTful API serving JSONs.
General advice:
Flux is a quite loose concept, and exact implementations change from team to team. I noticed that Facebook has changed some approaches here and there over time as well. The exact cycle is not strictly defined. There are some quite "fixed" things though:
There is a Dispatcher that dispatches all actions to all stores and permits only one action at the time to prevent event-chain hell.
Stores are action receivers, and all state must be changed through actions.
actions are "fire and forget" (no callbacks!)
Views receive state from the store and fire actions
Other things are done differently from implementation to implementation
Is it correct/highly advisable to have all of my $.ajax calls inside my Web API Utils? Callbacks call the action creators, passing the data in the process.
Absolutely.
If I want my Store to make an AJAX call, I do have to call the Action Creator first, right? Is it fundamentally incorrect to call a function in Web API Utils directly from Store?
First, ask yourself why your store needs to do an API call. The only reason I can think of is that you want to cache the received data in the stores (I do this).
In the most simple Flux implementations, all Actions are created from only the View and Server. For example, a user visits a "Profile" view, the view calls a profileRequest action creator, the ApiUtils is called, some data comes in, a ServerAction is created, the ProfileStore updates itself and the ProfileView does accordingly.
With caching: the ProfileView ask the ProfileStore for some profile, the store doesn't have it, so returns an empty object with state 'loading', and calls ApiUtils to fetch that profile (and forgets about it). When the call finishes, a ServerAction will be created, the ProfileStore will update itself, etc. This works fine. You could also call and ActionCreator from the store, but I don't see the benefit.
MartyJS does something similar. Some flux implementations do the same with promises.
I think the important part is: when data comes back into the system, a ServerActionCreator is called with the new data. This then flows back into the stores.
I believe stores should only query data, all state-changing actions (updating stuff) should be user-initiated (come from views). Engineers from Facebook wrote about this here: https://news.ycombinator.com/item?id=7719957
Is there like a virtual one-sided arrow connecting from Store to Action Creators?
If you want your stores to be smart: yes. If you want your app to be simple: no, go through Views.
What are the Callbacks between Dispatcher and Store?
These are the dispatch handlers you find in stores. The dispatcher fires an action, stores listen to this fire event and do something with the action/payload.
What's the Web API here? Is this where you'd apply a RESTful API? Is there an example of this somewhere?
This is where your ajax calls go. Typically this will mean some REST API, but could als be websockets or whatever. I've always loves this tutorial: http://fancypixel.github.io/blog/2015/01/29/react-plus-flux-backed-by-rails-api-part-2/
Disclaimers: these are my interpretations of Flux. Flux itself doesn't really solve fetching data, that's why they've come up with Relay and GraphQL at FB