Reputation: 22994
Looking for some advice when working with Redux, and Angular. I've been researching Redux for the past couple of days and really think its a great way to store application data. The part I'm having trouble with is whether to persist everything within the store or only certain parts. Ideally, I think the entire application should be running through the store, but for forms this seems very tedious.
For example, lets say I'm working with a form to add a new product. Here are some of my pain points.
I would like to keep the User Reducer (store) separated from the actual form state. Should I create a separate form reducer per component?
Having to persist every input field back to the store sounds like a lot of work. I've seen the library redux-form simplifies this, but is intended for React.
Anyone have any good advice when it comes to creating forms in Angular with Redux?
Upvotes: 5
Views: 1656
Reputation: 6798
The answer is "it depends". Also, the assumption is that you''re convinced of the benefits of one-way data flow and redux, so prefer redux over two-way data binding if given the choice.
The common use case is actually very simple. A concrete example will help---suppose the form tracks app settings, meanwhile app settings
exist as redux state. That is, there is a two-way data binding between the Angular form and the redux state. This is probably the common use case.
In this case, the solution is to proceed as before: update redux state from the Angular form by dispatching update actions, and update the Angular form from redux state via #mapStateToThis.
Angular ----dispatch actions-----> Redux
Form <----mapStateToThis-------- State
The only gotcha is to not pass the Redux state directly to the Angular form i.e., deep clone the data or use ImmutableJS.
The other common use case is to implement a "form reset", that is, reset the form to a "pristine" state after pressing a button, for example. Again, a concrete example will help:
Suppose that
app state
(redux state) tracks whether the state is pristine via a flagapp.pristine
. (To clarify howapp.pristine
works, it works as expected, that is, it changes to false as soon as any value changes, and changes to true only when explicitly set to true.)
First, as far as I know, Angular doesn't automagically keep track of the "initial" state. You have to do it yourself and you may as well put that state in redux. Then, the initial form values are just the app settings when app.pristine
is false. (If you're thinking of putting this in #mapStateToThis, don't. Doing side effects in a transform function seems weird.) A better way is to use an asynchronous action, namely the form onChange listener:
// thunk example
onFormChange(newForm) {
return (dispatch, getState) => {
const appSettings = getState().appSettings;
const appIsPristine = appSettings.pristine;
// this will fire once because the next action will set it to false
appIsPristine && dispatch(initForm(appSettings)));
dispatch(updateAppSettings(newForm));
};
},
The reset action works as you would expect (which I won't outline).
To conclude, I should add that the above assumes that only the Angular form can dirty the app settings---otherwise, the initial form values may never be stored. If that's the case, then one idiomatic solution is to create a custom middleware that sets the initial form value whenever app.pristine
changes to true. (Alternatively, use an Angular watch.)
Upvotes: 4