Flux- infinite scroll: i cannot think of how to stick to unidirectional data flow - reactjs-flux

i am trying to implement an infinite scroll from many items that i get from the server, but i cannot find any proper way to keep the flux architecture design rules.
the idea is: on the first load, i get a full item list from server (only id's), then using ajax i fetch each time 20 more items.
the list is kept in the Store, and also the loaded items. the view listens on loaded items and render them, when it reaches scroll bottom it calls an action which should then fetch 20 more items, and so on.
the problem is: the Action should know what items to fetch, the unloaded items list is in the store, so it has to get it from the store directly, which is a "don't do it' in flux. other alternatives are to handle all the logic in the stores, which seems also a bad idea..
can anyone think of a nice solution?

UPDATE: it is OK within unidirectional flow for a component to read directly from store (see below)
Make your action explicitly say which items to fetch: "Give me items 21-40 please".
This fires a) (async) ajax call to get items 21-40 and b) dispatch to the store.
The component knows a) which items it has already rendered, and b) which items the user wants to see next, so it can pass along the above action message without talking to the store again.
The store receives the request. The store knows it does not have the items yet. The component does not know yet.
Store emits change, and your component (assuming it is listening to store changes) gets current state from store. If the items weren't there, the store provides a loading state ("loading items 21-40" or similar). The component displays the loading state. (or, if the loaded items are already fully in store, it simply renders items 21-40).
As soon as items 21-40 are delivered by ajax return, your store updates with the full items 21-40. (if they happened to be in store already, no problem, no update). Store emits another change. Component hears this, and re-renders.
ASIDE:
Unidirectional flow is for updates:
Component -> lower components -> actions (-> webAPI -> action) -> dispatcher -> stores -> components
In unidirectional flow rules are:
Components are allowed to push data updates only to lower components (by passing new props, which trigger re-render), not to higher components
Components are allowed to maintain an internal state, which they can pass on as props to children (see 1)
Components are allowed to push data updates or update requests also to the dispatcher (in "actions"). The dispatcher then forwards the updates to the stores and/or to some server via eg webAPI.
Components are allowed to listen to store changes and pull/ read data directly from the store.
Stores listen to the dispatcher, and update if they receive news from the dispatcher.
Stores may also listen to other stores, and read data from other stores to update themselves
Stores emit change as soon as they have updated, so that any components listening can do something (typically read new data) (see 4.)
WebAPI results from the server are "actions". They go through dispatcher which informs the relevant stores to update. (See 5)
Unidirectional flow breaks if:
Component actively fetches/ pulls data from a higher component - such data should be pushed by higher component as props (see 1)
Component actively fetches data from child - as parent, component should already have this data. If it is in child's state, then state is designed at too low level.
Component directly updates store - should be with an action through dispatcher
And also breaks if (although some disagree):
Store directly updates another store - should be pull instead of push (see 6)
Store pushes update through an action - only webAPI (see 8) and components (see 3) are allowed to issue actions
Component directly does webAPI request and handles result in state - should go through dispatcher

Related

Alt data dependency between actions not stores

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.

How to manage state in a Flux/ReactJS app with Stores?

In a FLUX/ReactJS arhitecture, I am curious if the following approach violates (or is just not recommended) the FLUX flow.
1) We have 2 stores. Store A & Store B.
2) We have one "App" Component which has its State set from Store A and passes it down to Component 1 and Component 2.
3) Component 1 uses the data from the received "this.props" and renders stuff.
4) Component 2 uses data from the received "this.props" but also has its own state based on Store B (the same way "App Component" has its state).
From what I understand - ideally - I would make the "App Component" listen to both Store A & Store B and pass everything down to the other components.
However, in a real life application, you'd have let's say 100 stores, each with its own conditions (you could say Component 2 doesn't get rendered if a certain combo of data is not met, etc). That would make the App Component a GOD-like component which handles so much stuff. Impractical in my mind.
In my mind, you still get a one-direction flow of data even if you don't have a top component managing all state and passing it down to the components - since the state is still dictated by the Stores, not by the components themselves (and you trigger events via Actions->Dispatcher->Store). This is especially good in my mind if you want to encapsulate a certain behavior in a component.
Imagine the following scenario:
AppComponent -> AuthComponent -> LoginFormComponent
AppComponent -> ListItemsComponent -> SingleItemComponent
Wouldn't it be weird if AppComponent knew about the "AuthStore" state, just so it can pass it to the AuthComponent via props ?
Wouldn't it be better if the AppComponent knew nothing (in this example) and just renderered the 2 children;
The AuthComponent would listen to the AuthStore and pass down info to the
LoginForm;
The ListItemsComponent would listen to a ListItemsStore and pass down the needed info to SIngleItemComponent etc..
Which approach would you guys take?
Theoretically If your lower level component is completely isolated and there is 0% chance that, depending on its state, you would need to change the state of higher level (or the same level) components, then there is nothing wrong with managing its state within the component itself.
There are downsides however:
If later you decide to use the state of the component higher in the
hierarchy you'd need to refactor.
It makes a component less
reusable. You'd need to have same store, same actions etc. whereas if you received state via props you could plug it into other project much more easily.
It makes it harder to test.
I would say that if it's a large independent component, with many lower components it makes sense to keep the state within it, but usually there is only one such component in the app. If it's more of a small, one purpose component, there is no point in doing this.

Tracking ajax request status in a Flux application

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.

AngularJs - Persistence, storage, ajax requests, data integrity

I'm evaluating whether AngularJS will work as a solution for my moderately simple web application.
The aim is to cut down the amount of AJAX server requests for data as much as possible.
My actual question is simple, yet the repercussions of that request is leading to confusion.
In a nutshell: "Can Angular modify parts of JSON data received from a backend through user input and maintain state until I'm ready to return that data.
Scenario:
Grab JSON data from the server that contains a root name & associated address details for each root name. The list is rendered to screen along with an 'Edit Address' button for each item.
The user clicks 'Edit Address', Angular displays a form with the address data for the root name.
The user edits the data, clicks submit, the client sends JSON data to the server and, for arguments sake, we get a success return. The address details are modified.
This is where the meat of my question - and lack of understanding - comes to the fore.
Do I need to get the entire list of 10 items back from the server with the single modified address details, just from editing a single list item OR can I simply update that single item client side and hold state as the user returns to the list, say, to edit another item?
IOW, we get a success, but no data is actually returned aside from 'success' - our client has stored the changes.
This is where the data integrity issue rears it's ugly head.
** OR **
Grab a list of root items without associated address data.
The user clicks on an 'Edit Address' button for the root item.
We fetch the address data for the root name from the server and the form is displayed, the user edits the data, submits, send data asynchronously, get a success.
User returns to the list and another server request is made to grab the list from the server again.
This is hellishly difficult to explain, but the bottom line is about persistence and data integrity.
Is it best practice to make a server requests after each user edit of data, or can modified data be stored client side - with persistence?
obviously validation will be done server side, as well as client side.
What you're asking is more of a server-side question, on how to design a good RESTful API that allows changes to individual entities without sending/loading the entire list each time. So the answer to your question is that it's entirely up to you... angular does a great job of binding UI elements to the javascript objects in your controllers for you, but when it comes time to save that data to the server, you can do it however you want.
In an ideal world (IMO) your server-side API would support the following:
Get a list of addresses (angular stores them in $scope.addresses)
Get a single address
PUT/PATCH to update an address (when a user makes a change to a single address and confirms it) and return 204 no content
POST to create new addresses, and return the created address with a server-provided identifier (like "id"), that you can use in angular to determine whether an address has been persisted server-side or not. After POSTing, you rewrite the angular scope object with what you got from the server to save the id field.
DELETE to remove them (returning nothing)
With this, when you have the client create an address, you should send a POST to the server to create one, take the response JSON and copy it over the object you just saved, so that now it has an "id" field (or similar). You can use angular templates to visually represent that anything with an "id" field is saved to the server. This way you don't have to re-grab the whole list every time you save.
For updating addresses, this is why PATCH is useful: you can send only the changes to individual fields to the server and ensure that only things the user has changed get sent.
Deleting addresses can work by checking if the "id" field is there, and if so, send a DELETE to the server, and if not, the object was never "saved", so just remove the address from the scope. Upon successful deletion you can just remove the address from the scope, no need to reload everything.
When it comes to the "data integrity", ie. if there's other addresses created since you've done the original data request, you'll have to do this on your own... Ideally similarly to how Stack Overflow or Github does it, which is to hint in the UI that there has been server-side changes and you should click to refresh. How to determine refreshes is up to you, but you can keep it simple with polling at intervals, or you can go all out and do WebSockets/Server-side events and actually push changes to the browser.
The best way to create UIs that persist to the server is a complicated topic and there are a lot of best practices. Angular will support whatever you want, but you need coordination on the server to do it.

Asynchronous data loading in flux stores

Say I have a TodoStore. The TodoStore is responsible for keeping my TODO items. Todo items are stored in a database.
I want to know what is the recommended way for loading all todo items into the store and how the views should interact with the store to load the TODO items on startup.
The first alternative is to create a loadTodos action that will retrieve the Todos from the database and emit a TODOS_LOADED event. Views will then call the loadTodos action and then listen to the TODOS_LOADED event and then update themselves by calling TodoStore.getTodos().
Another alternative is to not have a loadTodos action, and have a TodoStore.getTodos() that will return a promise with the existing TODO items. If the TodoStore has already loaded the TODO items, it just returns them; if not, then it will query from the database and return the retrieved items. In this case, even though the store now has loaded the TODO items, it will not emit a TODOS_LOADED event, since getTodos isn't an action.
function getTodos() {
if (loaded)
return Promise.resolve($todoItems);
else
return fetchTodoItemsFromDatabase().then(todoItems) {
loaded = true;
$todoItems = todoItems;
return $todoItems;
});
}
I'm sure many will say that that breaks the Flux architecture because the getTodos function is changing the store state, and store state should only be changed though actions sent in from the dispatcher.
However, if you consider that state for the TodoStore is the existing TODO items in the database, then getTodos isn't really changing any state. The TODO items are exactly the same, hence no view need to be updated or notified. The only thing is that now the store has already retrieved the data, so it is now cached in the store. From the View's perspective, it shouldn't really care about how the Store is implemented. It shouldn't really care if the store still needs to retrieve data from the database or not. All views care about is that they can use the Store to get the TODO items and that the Store will notify them when new TODO items are created, deleted, or changed.
Hence, in this scenario, views should just call TodoStore.getTodos() to render themselves on load, and register an event handler on TODO_CHANGE to be notified when they need to update themselves due to a addition, deletion, or change.
What do you think about these two solutions. Are they any other solutions?
The views do not have to be the entities that call loadTodos(). This can happen in a bootstrap file.
You're correct that you should try your best to restrict the data flow to actions inside the dispatch payload. Sometimes you need to derive data based on the state of other stores, and this is what Dispatcher.waitFor() is for.
What is Flux-like about your fetchTodoItemsFromDatabase() solution is that no other entity is setting data on the store. The store is updating itself. This is good.
My only serious criticism of this solution is that it could result in a delay in rendering if you are actually getting the initial data from the server. Ideally, you would send down some data with the HTML. You would also want to make sure to call for the stores' data within your controller-views' getInitialState() method.
Here is my opinion about that, very close to yours.
I maintain the state of my application in Store via Immutable.Record and Immutable.OrderedMap from Immutable.js
I have a top controller-view component that get its state from the Store.
Something such as the following :
function getInitialState() {
return {
todos: TodoStore.getAll()
}
}
TodoStore.getAll methods will retrieve the data from the server via a APIUtils.getTodos() request if it's internal _todos map is empty. I advocate for read data triggered in Store and write data triggered in ActionCreators.
By the time the request is processing, my component will render a simple loading spinner or something like that
When the request resolves, APIUtils trigger an action such as TODO_LIST_RECEIVE_SUCCESS or TODO_LIVE_RECEIVE_FAIL depending on the status of the response
My TodoStore will responds to these action by updating its internal state (populating it's internal Immutable.OrderedMap with Immutable.Record created from action payloads.
If you want to see an example through a basic implementation, take a look to this answer about React/Flux and xhr/routing/caching .
I know it's been a couple of years since this was asked, but it perfectly summed up the questions I am struggling with this week. So to help any others that may come across this question, I found this blog post that really helped me out by Nick Klepinger: "ngrx and Tour of Heroes".
It is specifically using Angular 2 and #ngrx/store, but answers your question very well.

Resources