I'm thinking about Flux architecture of React and I want to identify the best way of handling Ajax requests. See the example of a comment box in below picture.
The overall architecture is clear, my concern is: should we really need a separate store for saving a view's private state such as Ajax request is failed?
Why we have stores is because data could be reused by different views. But should a network result also reused for other views besides the view originates the request?
Whether the ajax request success or fail is also a state of the view such as setState({loading: true/false}). And this state is not related with the data result of the request. The private loading state may be related with different network requests such as post, refresh, delete etc. I know some people suggests to provide a ErrorStore for this scenario. But if we don't develop stateless component I can't see any reason we only save network state in a separate store.
So in my project I use Promise:
actionCreators.postComment({...})
.then(res => this.setState({loading: false, error: null}))
.catch(err => this.setState({loading: false, error: err}));
The above code corresponds to the red part of the picture.
So my question is: is this approach reasonable? Or does Redux/Reflux have better ways? Thanks.
I don't see an issue with storing the ajax request state in your store - you don't need a separate store just for that. You can keep the state within your view store.
In your diagram, where you have the condition "Success?", it can dispatch a success or failure action and the store can save the fact that the request was a success (you may wish to have some sort of non-blocking UI which disappears when this is successful).
A request may fail because of a model validation error, not just a network failure. In this case, it would be worthwhile storing these errors into the store, there's no harm in it.
One of the benefits of the Flux architecture is that there's single, defined flow of data, however in your diagram the flow of data is conditional depending on the success of ajax requests. If you keep request states within your store, sent via dispatches, then you will maintain that single flow of data.
Related
I've got a situation where I have a WebApi endpoint that my page polls for data every minute or so. Each poll returns about 10KB of data, and I've realized that in many cases the data doesn't change from the previous poll, but it still eats up the bandwidth sending back the results.
So I'm wondering if there's a standard way to have WebApi determine that the results haven't changed AND to signal the browser that this is the case.
Because the endpoints are stateless, how could an endpoint know what the previous state was?
And how should it signal the client that this is the case? In most situations, I return a strongly typed object (like List<T>), so I can't instead return some other UseCachedVersion kind of object. I could return null, but that isn't as descriptive as I would like.
Are there any standard practices for this situation?
You use caching in the API/controller layer like CacheOutput. http://www.hanselman.com/blog/NuGetPackageOfTheWeekASPNETWebAPICachingWithCacheCowAndCacheOutput.aspx
If you need real-time update to the poll, you can use SignalR and just update the client/subscribers if the server makes a broadcast.
I have a react app where I'm using alt for the flux architecture side of things.
I have a situation where I have two stores which are fed by ajax calls in their corresponding actions.
Having read the alt getting started page on data dependencies it mentions dependencies between stores using waitFor - http://alt.js.org/guide/wait-for/ but I don't see a way to use this kind of approach if one of my store actions is dependent on another store action (both of which are async).
If I was doing this inside a single action handler, I might return or chain some promises but I'm not sure how to implement this across action handlers. Has anyone achieved this? or am I going about my usage of ajax in react the wrong way?
EDIT: More detail.
In my example I have a list of nodes defined in a local json config file, my node-store makes an ajax request to get the node detail.
Once it's complete, a different component (with a different action handler and store) wants to use the node collection to make an ajax query to different endpoints a node may expose.
The nodes are re-used across many different components so I don't want to roll their functionality into several different stores/action handlers if possible.
We're refactoring a large Backbone application to use Flux to help solve some tight coupling and event / data flow issues. However, we haven't yet figured out how to handle cases where we need to know the status of a specific ajax request
When a controller component requests some data from a flux store, and that data has not yet been loaded, we trigger an ajax request to fetch the data. We dispatch one action when the request is initiated, and another on success or failure.
This is sufficient to load the correct data, and update the stores once the data has been loaded. But, we have some cases where we need to know whether a certain ajax request is pending or completed - sometimes just to display a spinner in one or more views, or sometimes to block other actions until the data is loaded.
Are there any patterns that people are using for this sort of behavior in flux/react apps? here are a few approaches I've considered:
Have a 'request status' store that knows whether there is a pending, completed, or failed request of any type. This works well for simple cases like 'is there a pending request for workout data', but becomes complicated if we want to get more granular 'is there a pending request for workout id 123'
Have all of the stores track whether the relevant data requests are pending or not, and return that status data as part of the store api - i.e. WorkoutStore.getWorkout would return something like { status: 'pending', data: {} }. The problem with this approach is that it seems like this sort of state shouldn't be mixed in with the domain data as it's really a separate concern. Also, now every consumer of the workout store api needs to handle this 'response with status' instead of just the relevant domain data
Ignore request status - either the data is there and the controller/view act on it, or the data isn't there and the controller/view don't act on it. Simpler, but probably not sufficient for our purposes
The solutions to this problem vary quite a bit based on the needs of the application, and I can't say that I know of a one-size-fits-all solution.
Often, #3 is fine, and your React components simply decide whether to show a spinner based on whether a prop is null.
When you need better tracking of requests, you may need this tracking at the level of the request itself, or you might instead need this at the level of the data that is being updated. These are two different needs that require similar, but slightly different approaches. Both solutions use a client-side id to track the request, like you have described in #1.
If the component that calls the action creator needs to know the state of the request, you create a requestID and hang on to that in this.state. Later, the component will examine a collection of requests passed down through props to see if the requestID is present as a key. If so, it can read the request status there, and clear the state. A RequestStore sounds like a fine place to store and manage that state.
However, if you need to know the status of the request at the level of a particular record, one way to manage this is to have your records in the store hold on to both a clientID and a more canonical (server-side) id. This way you can create the clientID as part of an optimistic update, and when the response comes back from the server, you can clear the clientID.
Another solution that we've been using on a few projects at Facebook is to create an action queue as an adjunct to the store. The action queue is a second storage area. All of your getters draw from both the store itself and the data in the action queue. So your optimistic updates don't actually update the store until the response comes back from the server.
In angular, there doesn't seem to be a built-in way to store model lifecycle state, that is, the state that is due to it being an asynchronous and potentially out of date copy of a remote model stored on the server, or where the server would be out of date compared to the client. Looking at how Ember does it, at http://emberjs.com/guides/models/model-lifecycle/ , they have a number of states for Model objects:
LOADING
LOADED/CLEAN
DIRTY
IN-FLIGHT
INVALID
ERROR
Angular's models seem to just be plain old Javascript objects, and so don't have this. Looking at $resource, which seems to be closer to what I'm looking for, doesn't seem to have anything to do with state either. My aim is to make it clear to the user when something needs to be saved to the server, and the result of any such saving.
What would be a good way of doing this?
Are there any existing libraries for this, or would I have to roll my own?
Edit: I'm not referring the DOM being out of date compared to the model in the memory of the browser. I understand the Angular handles all that as the 2 way data binding as explained at http://docs.angularjs.org/guide/dev_guide.templates.databinding . This is handling the states when the model might itself be different compared to the server.
Did you have a look at the form directive ? You can check whether it's pristine, dirty, valid etc... This could fulfill your need to "make it clear to the user when something needs to be saved to the server". I don't really know what you mean by "the result of any such saving.", but based on the state of the form, you could display anything you want.
Background
I'm working on a web application utilizing AJAX to fetch content/data and what have you - nothing out of the ordinary.
On the server-side certain events can happen that the client-side JavaScript framework needs to be notified about and vice versa. These events are not always related to the users immediate actions. It is not an option to wait for the next page refresh to include them in the document or to stick them in some hidden fields because the user might never submit a form.
Right now it is design in such a way that events to and from the server are riding a long with the users requests. For instance if the user clicks a 'view details' link this would fire a request to the server to fetch some HTML or JSON with details about the clicked item. Along with this request or rather the response, a server-side (invoked) event will return with the content.
Question/issue 1:
I'm unsure how to control the queue of events going to the server. They can ride along with user invoked events, but what if these does not occur, the events will get lost. I imagine having a timer setup up to send these events to the server in the case the user does not perform some action. What do you think?
Question/issue 2:
With regards to the responds, some being requested as HTML some as JSON it is a bit tricky as I would have to somehow wrap al this data for allow for both formalized (and unrelated) events and perhaps HTML content, depending on the request, to return to the client. Any suggestions? anything I should be away about, for instance returning HTML content wrapped in a JSON bundle?
Update:
Do you know of any framework that uses an approach like this, that I can look at for inspiration (that is a framework that wraps events/requests in a package along with data)?
I am tackling a similar problem to yours at the moment. On your first question, I was thinking of implementing some sort of timer on the client side that makes an asycnhronous call for the content on expiry.
On your second question, I normaly just return JSON representing the data I need, and then present it by manipulating the Document model. I prefer to keep things consistent.
As for best practices, I cant say for sure that what I am doing is or complies to any best practice, but it works for our present requirement.
You might want to also consider the performance impact of having multiple clients making asynchrounous calls to your web server at regular intervals.