Need to have selectors update when action handler does not update model due to invalid data.
Looking for a strategy to handle actions that would invalidate state so are dismissed. Components often fire actions with data and the state action handler determines invalid so does not update state with invalid data. However, without the update, selectors do not fire so component is left in invalid state. Memoization is great but need a mechanism to force a selector update so that components will bind correctly.
Looked at binding to the entire state, double updates, wrapping values in complex objects but all seem like hacks to a common cross cutting concern. Any patterns out there i might be missing.
Related
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.
Let say I have a stream of persisted events that build a valid state according to some "schema" I have defined.
I change the schema and the events are upgraded to reflect this.
However, some state could not be made valid just by upgrading events, I also needed to add more events to patch the state to make it fully valid.
Firstly, is this reasoning at all valid in terms of event sourcing?
If so, how do I handle cases where a specific version of a state no longer becomes valid? I mean is this acceptable? Should it still be possible to rehydrate a version with invalid state? If this is a write model and it's not the latest version, I could not modify this state anyway so maybee it's no big deal?
However, some state could not be made valid just by upgrading events, I also needed to add more events to patch the state to make it fully valid.
"Compensating events" is the usual term; there is a clerical error in the book of record, so we need to add a new event to the history that corrects the mistake.
If so, how do I handle cases where a specific version of a state no longer becomes valid?
As a rule, you want to be wary, extremely wary, of introducing any automated validation that prevents you from loading an invalid history. Remember, state is just state; the business rules constrain the way the domain is allowed to change. Leaving broken states readable, but broken, is safe.
In particular, if you allow the state to load, it is a straight forward exercise to enumerate your event streams, test the final state of the object, and produce an exception report for any streams that produce an invalid state, escalating them to operators/management for handling, and so on.
Assuming that you are reasonable careful about input validation, and comparing whether your proposed command is consistent with latest known state (aggregates enforce business rules, but they don't need to hoard those rules for themselves), then you can probably achieve error rates low enough that you don't need aggressive data validation. That's especially true when the errors are easy to detect and cheap to fix.
Failing that, freezing any aggregates while they are in an invalid state is a good way to prevent further damage.
But if you really need the state to stay valid, there's a trick that you can play with compensating events.
Consider: the basic pattern of event sourcing looks something like
History history = repository.getHistoryById(id)
State current = State.SEED
for (Event e : history) {
current = current.apply(e)
}
There's actually a hidden concept here, which encapsulates the logic for processing the events prior to passing them to the state. Hidden, because the null case just passes the enumerated events straight through to the target.
History history = repository.getHistoryById(id)
Historian historian = new Historian();
State current = State.SEED
for (Event e : historian.reviewEvents(history)) {
current = current.apply(e)
}
The historian gives you a place to put your compensating event logic - based on its own state, the historian passes through most events, but fixes the ones that knows needs edits/compensation/redactions
Where does the historian state come from? Why, from the history of the historian, of course. You load the history of the event corrections, which will typically be short, into the historian, and then let the historian clean up the events for the aggregate.
And if you need corrections for the historian? It's turtles all the way down! Each stream has a unique historian; the identifier for the historian's stream is calculated from the stream it filters (named UUID's, for example, would allow you to do this). So for each stream, you check to see if a historian stream exists; when you find one that doesn't, you know to stop searching and use the null historian, roll up the changes, process the final sequence of events to regenerate the state of your real object, and off you go.
Mind you, I haven't seen a reference implementation of this idea anywhere; it's whiteboard sound, but the truth is I've been deferring this requirement in my own designs.
I am trying to understand how immutability is actually (if at all) used in Redux. Every tutorial/article/document I found states that reducers should never alter the state object but instead create a new copy of the changed data (i.e. the reducers must be pure functions). I understand this but I could not find any place where there is an explanation of how this guideline is actually used by Redux internal implementation.
Is this just a strong recomendation or will something inside Redux breaks if I make the reducers non pure?
If it is the later then what exactly will break?
I did find several places where Dan says that in some (very rare) cases the reducers may be non pure but it is risky (again, with no explanation what is the risk exactly).
Redux, when used with React, is typically connected by using connect from react-redux. Wrapping a component with connect, makes it subscribe to changes to the redux store by specifying a change handler, which gets invoked after an action is dispatched and the reducers are called. Upon invocation of the change handler, connect compares the current state of the store with the new state using identity comparison (previousState !== newState) – which is faster than doing a shallow or deep comparison – and only when the two states aren't identical, does it update the wrapped component using setState. Mutating the state directly will not cause the references to change, thereby causing the wrapped component to not re-render.
This is how connect determines if it should call setState:
if (!pure || prevStoreState !== storeState) {
this.hasStoreStateChanged = true
this.setState({ storeState })
}
connect also provides an option to override this behaviour by specifying that the wrapped component is not pure using:
connect(mapStateToProps, mapDispatchToProps, mergeProps, {pure: false} )
Identity comparison is also used by pure components by implementing shouldComponentUpdate to prevent unnecessary calls to render.
TL;DR: a component wrapped with connect will not re-render if a store's state changes due to mutation.
Edit: Nothing in Redux itself will break since it is so minimal that it doesn't try to inspect the state returned by reducers.
I have a React.js application that I am refactoring to use the Flux architecture, and am struggling to figure out how error handling should work while sticking to the Flux pattern.
Currently when errors are encountered, a jQuery event 'AppError' is triggered and a generic Error Handling helper that subscribes to this event puts a Flash message on the user's screen, logs to the console, and reports it via an API call. What is nice is I can trigger an error for any reason from any part of the application and have it handled in a consistant way.
I can't seem to figure out how to apply a similar paradigm with the Flux architecture. Here are the two particular scenarios I'm struggling with.
1) An API call fails
All of my API calls are made from action creators and I use a promise to dispatch an error event (IE 'LOAD_TODOS_FAILED') on failure. The store sees this event and updates it's state accordingly, but I still dont have my generic error behavior from my the previous iteration (notifications, etc).
Possible resolution:
I could create an ErrorStore that binds to the 'LOAD_TODOS_FAILED' action, but that means every time I have a new type of error, I need to explicitly add that action to the ErrorStore, instead of having all errors be automatically handled.
2) Store receives an unexpected action
This is the one I'm really confused about. I want to handle cases when an action is dispatched to a Store that does not make sense given the Store's current state. I can handle the error within the Store to clean up the state, but still may want to trigger an error that something unexpected happen.
Possible resolutions:
Dispatch a new action from the store indicating the error.
I believe Stores are not suppose to dispatch actions (let me know if I'm wrong), and I still have the same issue as with an API error above.
Create a ControllerView for Error Handling that subscribes to every Store
I could define an errors property on every store, then have a View watching every Store and only act on the errors property. When the errors property is not null, it could dispatch new actions, etc. The disadvantages are that I need to remember to add every Store to this view whenever new ones are created, and every store has to have an error property that behaves the same way. It also does nothing to address API call failures.
Does anyone have a suggested approach for a generic Error Handler that fits into the Flux architecture?
TL;DR
I need to handle errors in most Action Creators and Stores. How do I setup consistent error handling that will occur for any type of generic error?
API call fails
If you want to avoid listing every error action in the ErrorStore, you could have a generic APP_ERROR action, and have properties of that action that describe it in more detail. Then your other stores would simply need to examine those properties to see if the action is relevant to them. There is no rule that the registered callback in the stores needs to be focused on the action's type, or only on the type -- it's just often the most convenient and consistent way of determining if an action is relevant.
Store receives an unexpected action
Don't issue a new action in response to an action. This results in a dispatch-within-a-dispatch error, and would lead to cascading updates. Instead, determine what action should be dispatched ahead of time. You can query the stores before issuing an action, if that helps.
Your second solution sounds good, but the dangerous thing you mentioned is "When the errors property is not null, it could dispatch new actions, etc" -- again, you don't want to issue actions in response to other actions. That is the path of pain that Flux seeks to avoid. Your new controller-view would simply get the values from the stores and respond by presenting the correct view.
I am not sure if this is possible, but I have a scenario where I have a validation system which notifies my validation system when something has become valid/invalid via a dependant observable. Now this works great when a user is filling out a form as the dependantObservable is driven off the underlying observables value changing. (i.e if the Name property changes, it will re-evaluate the isValid dependant observable, which will in turn notify my binding which hooks into the validation system).
Now my problem is that if the user doesn't touch the form at all and just goes straight to submission, it will not trigger the binding, as the underlying values have not changed for any observables, so no subscribers will know about any validation changes happening. Ideally I do not want to go through each observable and re-assign it its current variable to push a validation evaluation through, which would in turn trigger a change in the validation state. So as really all I want to do is get this isValid dependantObservable to refresh for lack of a better word.
It seems quite nasty either way, but my options seem to be either:
1) Force a value change on all observables being validated against (horrible)
2) Force a re-evaluation of the isValid dependantObservable to trigger the subscriber (less horrible, but still bad)
3) Re-write the validation library to expose a forceValidation() function which would somehow trigger everything to be re-evaluated, bypassing the need for the underlying observables to trigger the validation pipeline.
Any ideas?
On your computed observable (isValid) you can call notifySubscribers(currentValue), which will notify any subscribers with the current value. It will not re-evaluate the computed and will simply notify subscribers with the current value.
Add binding enable: formValid where formValid = ko.computed(return true if all values are valid) to submit button. This way user can not submit until form is filled properly.
Use ko.validation.validateObservable(yourDependentObservable) to revalidate field manually
or use yourObsevable.notifySubscribers() if yourDependentObservable depends on yourObservable.