I'm interested in thoughts on the best way to solve the following problem. I maintain a state in react-redux, could be anything, a collection of entities for example. I only update the state if I persist (via API call) or retrieve entities from the server. I have a form where I can edit the entity prior to persisting it (let's assume this is not a singleton form, but an active form per entity for argument's sake). Basically the problem I am trying to solve is how to retain a scratchpad copy of the entity in the redux store to be bound to the form components, to be persisted (back to the server and to the store) only when the entire form edit is complete (not bound in the form directly to the store via the state), as each edit would then require a round-trip to the server and it wouldn't be very performant. Ideas are welcome. Thanks.
So the solution I decided upon is as follows:
Take a copy of a given entity from the redux state and keep it in the local state when editing begins.
Editing occurs against the redux state via an entity persistence action. This way the redux state is always up to date.
If editing is aborted, the copy gets persisted back to the redux state.
Once editing is complete an async action is dispatched to persist the entity. View state is already up to date.
This seems to work for me.
Related
I'm developing small CQRS+ES framework and develop applications with it. In my system, I should log some action of the client and use it for analytics, statistics and maybe in the future do something in domain with it. For example, client (on web) download some resource(s) and I need save date, time, type (download, partial,...), from region or country (maybe IP), etc. after that in some view client can see count of download or some complex report. I'm not sure how to implement this feather.
First solution creates analytic context and some aggregate, in each client action send some command like IncreaseDownloadCounter(resourced) them handle the command and raise domain event's and updating view, but in this scenario first download occurred and after that, I send command so this is not really command and on other side version conflict increase.
The second solution is raising event, from client side and update the view model base on it, but in this type of handling my event not store in event store because it's not raise by command and never change any domain context. If is store it in event store, no aggregate to handle it after fetch for some other use.
Third solution is raising event, from client side and I store it on other database may be for each type of event have special table, but in this manner of event handle I have multiple event storage with different schema and difficult on recreating view models and trace events for recreating contexts states so in future if I add some domain for use this type of event's it's difficult to use events.
What is the best approach and solution for this scenario?
First solution creates analytic context and some aggregate
Unquestionably the wrong answer; the event has already happened, so it is too late for the domain model to complain.
What you have is a stream of events. Putting them in the same event store that you use for your aggregate event streams is fine. Putting them in a separate store is also fine. So you are going to need some other constraint to make a good choice.
Typically, reads vastly outnumber writes, so one concern might be that these events are going to saturate the domain store. That might push you towards storing these events separately from your data model (prior art: we typically keep the business data in our persistent book of record, but the sequence of http requests received by the server is typically written instead to a log...)
If you are supporting an operational view, push on the requirement that the state be recovered after a restart. You might be able to get by with building your view off of an in memory model of the event counts, and use something more practical for the representations of the events.
Thanks for your complete answer, so I should create something like the ES schema without some field (aggregate name or type, version, etc.) and collect client event in that repository, some offline process read and update read model or create command to do something on domain space.
Something like that, yes. If the view for the client doesn't actually require any validation by your model at all, then building the read model from the externally provided events is fine.
Are you recommending save some claim or authorization token of the user and sender app for validation in another process?
Maybe, maybe not. The token describes the authority of the event; our own event handler is the authority for the command(s) that is/are derived from the events. It's an interesting question that probably requires more context -- I'd suggest you open a new question on that point.
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
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.
What are the major disadvantages in using a form bean with session scope in struts 1.x?
You need to implement reset() if your form contains attributes populated from checkboxes. You don't need that to request-scoped form beans.
You need to reset the form to its default values if you show a creation form for the second time, else the creation form will redisplay the data coming from the last created/updated object.
You can't have two browser tabs or frames using the same form, because they will walk on each other's toes.
Form beans should be in the request scope by default.
Just try to work with both scopes and choose one preferred for yourself. But I should say there is small difference when you are working with persistent objects (and ORM tools like Hibernate), just because properties are persisted in database between requests.
Infamous checkboxes (and corresponding boolean properties). If you are working with persistent objects (editing boolean properties of some entity), you'll need extra code to reset checkboxes anyways. Scope doesn't matter because boolean property is persistent (isn't cleared automatically between requests).
When you are working with complex persistent objects (hierarchies of objects, mapped by Hibernate onto set of related database tables), often you'll just nest persistent object into form-bean and use nested properties, e.g. <html:text property="purchase.client.name" /> (of course, you can create getters/setters in form-bean for each property of the entire hierarchy, but this is tedious and will complicate further development). For creation you'll just create new empty purchase object in form-bean, for edition you'll load existing purchase from database (request for edit will contain some identifier of object you want to change). Scope doesn't matter again.
About two browser tabs. More important and underestimated problem arises with usage of AJAX requests, especially when they are not idempotent and are overlapped in time (browser issues request for update 1, then request for update 2, while update 1 is still processed on server) - although it is very strange design (I mean overlapping update requests simultaneously in one session from one user). Yes, in that case you'll need to separate data in different requests. But moreover, your action (if we are talking about Struts 1) should be thread-safe, and your business logic should be ready to concurrent/conflicting updates (solve synchronization problems, lock objects, merge/override/reject updates etc.). If you are developing multi-user application, this may happen also when two different users want to change the same object simultaneously. Again, bean scope has little importance comparing to the whole problem.
As you can see, there is only one disadvantage with session-scoped form bean, and it arises only in relation to serious design flaw (overlapping update requests from one user).
Is it possible to have one model that you break up into several views so that the user is not overwhelmed by the amount of data they will need to input? I'm trying to build a turbo tax like interface where a question or two are asked, then the user clicks next to answer the next set of questions and so on.
The Model doesn't seem make sense to break up into more models. Since it is a single distinct entity, like a questionnare.
See similar question for a nice example:
multi-step registration process issues in asp.net mvc (splitted viewmodels, single model)
It is possible to use the same model for multiple views, but you should decide how you want to preserve the state as you go though this "wizard". One approach can be to cross-post between the views and keep the state in post data, but in that case you have to add a lot of hidden fields for all model properties that are otherwise not displayed in an input on the current view. Another approach can be to persist the partially filled model, with the additional benefit, that the user might be able to continue after a session timeout or another problem, but then you might need to clean up stale data and be flexible in the validation on the database level. You can also preserve the state in the session if you want. Finally, you can also keep the state in the browser independent from the post data and do only AJAX calls with the server until you reach the point when you want to save everything.