Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

angular + redux/ngrx: state update vs. forms

Some context first, I'm using:

  • reselect for selectors
  • normalizr for normalization and denormalization
  • ngrx/store, which is a reactive implementation of redux, for state management

Now similarly to the react real world example I have a slice of state dedicated to entities, which is actually a requirement for denormalize() method of normalizr to work, since article can have an author, or media which could all be entities themselves.

Which means that when I'm selecting, for example, a single user from my state, I'm grabbing this global slice of entities, my selector looks something like this

export const getOne = createSelector(
  getAllEntities,
  getDetailId,
  (entities, id) => denormalize(id, schema, entities)
);

which is then being "selected" from ngrx/store with

state.map(getOne).distinctUntilChanged()

now to fill in my forms I do this (semi pseudo code)

class Cmp {
  form = new FormGroup({ /* whatever */});
  user$ = this._store.map(getOne).distinctUntilChanged();

  constructor(private _store: Store<AppState>) {
    this.user$.subscribe((data) => {
      this.form.patchValue(data);
    });
  }
}

with combination of reselect and map/distincUntilChanged I get a new update pretty much anytime any entity changes, so consider this situation..

  • you visit article id 5, it gets filled in with subscription to the store slice made of global entities slice
  • you start editing "text" FormControl
  • someone else changes an user with id 3 and you receive an update over websockets, causing the subscribe to trigger (since global entities slice changed) and overriding whatever value you changed while editing, with the value that is currently in the store (the old value)

..and there are quite a few different situation along this websocket that can cause an update update.

Is there any pattern in redux world that solves this, or has anyone in ngrx world had to deal with this? The only sensible thing that comes to my mind is saving whatever value to the store as you are typing, which would require hooking angular reactive forms to store, which is huge pain in the arse, and ngrx/forms are not coming anytime soon. But I'm sure someone must've came up with some simple solution already.

Thank you!

(you can read follow up discussion on gitter)

like image 259
fxck Avatar asked Apr 04 '17 20:04

fxck


People also ask

What is the difference between NgRx and Redux?

NgRx, which is the Angular version of Redux for React is for State Management. In React, state management can get complicated, and Redux is there to help. For Angular, this should not be the case as everything is synced due to two way data binding.

What is the difference between NgRx and NGXS?

As I have already mentioned, NGXS is a state management library which is very similar to NGRX, with the difference that it has less boilerplate code and is easier to learn. There are 4 basic concepts in NGXS that you should understand before you integrate it into your project.

When we should not use NgRx?

When should you not use NgRx? Never use NgRx if your application is a small one with just a couple of domains or if you want to deliver something quickly. It comes with a lot of boilerplate code, so in some scenarios it will make your coding more difficult.

Is it possible to manage more states using NgRx?

NgRx is a framework for building reactive applications in Angular. NgRx is inspired by the Redux pattern - unifying the events in your application and deriving state using RxJS. At a high level, NgRx stores a single state and uses actions to express state changes.


1 Answers

Consider storing the state of the form separately from the normalized entities. For example, your state could contain a property such as articleEditForm or something similar. Based on a subscription from your router state to get the id of the article, combineLatest with the current state of the store to dispatch an action of type 'EDIT_ARTICLE' with the payload of the article. The reducer would then set the articleEditForm property on your store state with article state payload. The original normalized entity would only be updated after a successful submission of the form - possibly using the values from articleEditForm or a response from the service the form was submitted to. This approach has the advantage of having the state of the form in your redux store for more sophisticated display and validation scenarios. The values could be updated in redux on every keystroke, input change, form submission, or whatever meets the needs of your use case may be.

This is overkill for 80% of simple forms - with the alternative to just populate forms directly from the normalized entity in the store (perhaps using .take(1) or using the router state and combineLatest with store to manage concurrency concerns). However, even just using vanilla forms, state is still managed separate from the normalized entities in your store - which is an accurate model of the problem IMO.

like image 117
Craig Smitham Avatar answered Sep 29 '22 00:09

Craig Smitham