I have an action, reducer, and service for some resource.
Let's assume in this case the resource is a cart, from which a user can have multiple of.
I have the following methods, getCartInformation, getCarts, getCartCount.
And I have the following API's, fetchCartInformation, fetchCarts, fetchCartCount.
getCarts returns the cart id's which are needed for getCartInformation and getCartCount
The question is, what would you do to avoid making multiple fetchCarts calls to the API whenever you call getCartInformation or getCartCount as a side-effect
Would you extend the API library with a fromCache flag, so that fetch*** has that option available.
Would you set a counter on the API library of "calls while querying the endpoint" and then just re-trigger the callers of the functions?
Would you add a check on the action to see if getState has already the cart, and if not query and re-trigger the function (might have 2 or more concurrent calls at the same time for a slow endpoint)?
Let's now assume that multiple components might trigger the getCartCount call, sometimes you want to call the endpoint when the component appears in the page and sometimes they all get called in the initialisation of the app because the components are all being added. In this case this will call the endpoints getCarts and getCartCount quite a couple of times.
Is there some kind of "redux-way" to catch that there's multiple calls to one method before it has already resolved?
Would you set a counter of calls on the getCarts action?
Would you make the action getCartCount depend on the getCarts promise response, and have a check on the getCarts action?
I know it's a bit complex and long question, but if there's more or less detail needed please let me know.
I do not understand why you should call getCarts whenever you call getCartInformation. Common use case is: (1) user see list of cards (by getCards) and (2) user click on one of them and see card info (by getCartInformation with id of selected card). Looks like you do not need to call getCards one more time.
It is usual to divide list of cards into pages. So you always have start, offset, total fields as service fields at every getCards call, so you do not need getCartsCount at all.
When I applied any kind of cache, it was reasonable to me to make it transparent for Redux, i.e. Redux action perform API call in usual way, and API layer decides (under the hood) should it send real ajax call or should it return data from cache.
Related
I'm having a trouble wrapping my head around following concept.
I'm sending OSC messages to query status of instruments in Ableton, so I have emmiter/receiver combo going on. Now, thing is that I'd like to avoid having to keep up some sort of global state and wrap everything around this.
and I do communicate with Ableto in following fashion:
sender.emit("/live/device", queryData);
receiver.on("/live/device", function(responseData){
// process response here...
})
So you can tell that I'm not really sure when I got data back and cannot really sequence new queries based on responses.
What I'd like to do is to simply
query number of instruments on ONE certain channel
get number back
query parameters of each instrument of that channel based on first query
receive parameters back
But problem is that I have no idea how to wrap eventListeners to respond to these queries, or rather how to sequence them in way that is non-blocking and yet still avoiding having some sort of global state going on.
Querying data and storing Promises to be resolved by eventListener seems like a solution, but then I'm stuck on how to pass them back to sequence.
After some research, it seems that this kind of behaving breaks the whole concept of event listeners, but then I suppose the whole point is to have some global state to keep track of what is going on, right?
Event listeners are telling you some asynchronous action coming from a user action or any other interrupt. Depending on the API you are facing, they might have re-used event listeners for replies instead of providing a promise or callback return for the send API. If the server has multiple clients interacting with it, it might want to tell all clients at the same time when their state changes as well.
If you are sure there is no way to directly provide a callback in the send method for a reply to your request or a request does not yield a promise that resolves with the reply at some point, there are usually workarounds.
Option 1: Send context, receive it back
There are APIs that allow sending a "context" object or string to the API. The API then sends this context to the event listeners whenever it answers this specific question along with their payload. This way, the context part of their payload can be checked if it's the answer to the request. You could write your own little wrapper functions for a more direct send/reply pattern then.
Option 2: Figure out the result data, if it fits your request
If the resulting data has something specific to match on, like keys on a JSON object, it may be possible to find out what the request was.
Option 3: Use state on your side to keep track of everything
In most cases where I have seen such APIs, the server didn't care much about requests and only sent out their current state if it was changed by some kind of request. The client needs to replicate the state of the server by listening to all events, if it wants to show the current server state.
In most situations where I faced this issue, I thought about Option 1 or 2 but ended up with Option 3 anyways: Other clients or hardware switches might interfere with my client UI and change the server state without me listening on that change. That way I would loose information that invalidates my UI, so I would need to listen and replicate the state of the server/machine/hardware anyways.
I'm working in a ReactJS and Meteor project and I found a strange behavior I'm gonna describe here:
There is a Tracker.autorun block with a Meteor.subscribe call inside. So far, so good. In the server side, there is a matching Meteor.publish which declares a callback.
As far as I understand, the Meteor.publish callback should fire once for each subscription received, but somehow this callback is firing 3~4 times for a single subscription.
In my last test the Tracker.autorun block executed 4 times, the subscribe only executed 1 single time and the callback fired 4 times.
The Meteor.subscribe only runs once, even the tracker runs several times. How could it cause the callback to fire more the once?
Does it make sense?
Do you know what could explain such behavior?
If you need any other information, just let me know.
Thanks in advance
Meteor.publish('current-user', function currentUser(credentials) {
return Users.find();
});
Tracker.autorun((c) => {
if (!currentUserHandler) {
currentUserHandler = Meteor.subscribe('current-user', this.credentials);
}
});
You should expect that the autorun will fire twice as a normal condition, once without data, and the second with some data.
That is to allow you to show a "loading" state before the data arrives.
You are subscribing to the users collection, which is a special collection. Meteor uses it for authentication, and also to record session activity. You are doing a Users.find(), which is an unfiltered query on the whole users collection, so any modification to any user will cause it to fire. You also won't be able to see all of the users records (for security reasons).
It's probable that you are storing additional data on the users record, hence the need for you to subscribe to it. I would recommend that you consider storing this data in another collection, such as 'members', 'visitors', 'profiles' or whatever name suits you. Things are likely to work better that way.
Say there is such a case:
In the state, there is a list, which corresponding to multiple rows in a table on the UI. There are multiple api calls, one for each item (row), which will retrieve the latest status, and update one item in the list.
In such case, I can understand that callback method will be better than direct call of setState. However, I still don't know whether multiple calls of the callback will be synchronized.
For example, whether the following situation will happen?
callback 1 reads list
callback 2 reads list
callback 1 updates list(0)
callback 2 updates list(1)
callback 1 writes back
callback 2 writes back
In such case, the update from 1 might be lost, which is typical for read-modify-write.
I still do not clearly understand your problem, perhaps if you could provide some code it would be better.
But if you meant to call a fetch function multiple times and setting the state once it's arrived, then you should be safe to assume that a setState should not override another, whether were your calls done asynchronously or synchronously.
But in any case, you shouldn't as a front-end send this much requests at once, you should request all the data from the server
The general problem: Let's say I have a button with an onClick handler calling an action creator. The action does an ajax call which dispatches a message when ajax responds, and this in some way affects the UI. Given this basic pattern there's nothing stopping the user from clicking this button multiple times, and thus running the ajax call multiple times.
This is something that doesn't seem to be touched upon in the React or Flux documentation (as far as I have seen), so I've tried to come up with some methods on my own.
Here are those methods
Use lodash.throttle on a method which does an ajax call so that multiple clicks in quick succession don't create multiple calls.
Use lodash.debounce on a method so that ajax is only called once a user hasn't done any activity for a bit. This is how I'm doing semi-realtime updates of text fields on change.
Dispatch an "is updating" message to stores when the action is first called and then dispatch a "done" message when the ajax call returns. Do stuff like disabling input on the initial message and then re-enable on the second.
The third method seems to be the best in terms of functionality since it allows you to make the user interface reflect exactly what's going on, but it's also incredibly verbose. It clutters absolutely everything up with tons of extra state, handler methods, etc...
I don't feel like any of these methods are really idiomatic. What is?
Hal is pretty much correct. Dispatching multiple messages is the Fluxiest way to go.
However, I would be wary of dispatching an IS_UPDATING message. This makes reasoning about your code harder because for each AJAX action you're dispatching several actions at once.
The idiomatic solution is to split your AJAX "actions" (action-creator-actions) into three dispatched actions: MY_ACTION, MY_ACTION_SUCCESS, MY_ACTION_FAILURE, handling each instance appropriately, and tracking "pending-ness" along the way.
For example:
// MyActionCreator.js
// because this is in a closure, you can even use the promise
// or whatever you want as a sort of "ID" to handle multiple
// requests at one time.
postMessage() {
dispatch('POST_MESSAGE', { ... } );
api.slowMessagePostingAjaxThingy().then(
(success) => { dispatch('POST_MESSAGE_SUCCESS', { ... }); },
(failure) => { dispatch('POST_MESSAGE_FAILURE', { ... }); }
);
}
// MyStore.js
on('POST_MESSAGE', (payload) => { /* do stuff */ });
on('POST_MESSAGE_SUCCESS', (payload) => { /* handle success */ });
on('POST_MESSAGE_FAILURE', (payload) => { /* handle failure */ });
This gives you several benefits over your alternate solutions:
Your store is exclusively in control of whether an item is pending or not. You don't have to worry about changing UI state on actions in your UI code: you can have your UI look exclusively to a pending property of your store for truth. This is probably the biggest reason for using Flux over MVC systems.
You have a clean interface for taking your actions. It's easy to reason about and easy to attach other stores to this data (if you have a LatestMessageStore or something, it's easy to subscribe to these events). This is the benefit over using IS_UPDATING as Hal suggested.
You save your lodash calls for when they semantically make sense— like when you may be inundated with legitimate data (a text field).
You can easily switch between optimistic updates (change the store when POST_MESSAGE is called) or pessimistic updates (change the store on POST_MESSAGE_SUCCESS).
I would argue that the third method is the correct way, but I don't find it to be verbose. A lot of React code that I see written sort of misses the spirit of React with its idea of very small, composable components. When large monolithic components are created, yes, things can get very messy.
But if the button in question is its own component, then it can take care of rendering based on its state. When a user clicks the button, the state of just that component changes -- and it renders it in a way that it can't be clicked again.
Once the store has notified that component that it has changed, the component can set its state back -- and with it, re-render itself.
It's a pretty straight-forward process; it just requires thinking about pages as a collection of small, composable units.
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