Binding to State - is this expected behaviour?

≯℡__Kan透↙ 提交于 2019-12-13 03:41:43

问题


I have a state that contains a collection of items:

import { State, Action, StateContext } from '@ngxs/store';
import {AddItem} from './app.actions';

export interface Item { 
  id: number;
  name: string;
}

export interface AppStateModel { 
   items: Item[];
}

@State<AppStateModel>({
  name: 'app',
  defaults: {
    items: []
  }
})
export class AppState { 

  @Action(AddItem)
  addItem(ctx: StateContext<AppStateModel>, action: AddItem){
     const state = ctx.getState();

        ctx.patchState({
            items: [
                ...state.items,
                { id: action.id, name: action.name}
            ]
        });
  }

}

My component is subscribed to the list of items in the store, when I add a new item that is reflected in the list displayed (all fine).

Observed behaviour

I then bind that displayed item to an input field - when I type in that input field I seem to be modifying the state of that item, i.e. the 'View Name' display of the item is also changing.

<ng-container *ngIf="app$ | async as app">

Name: <input #name />
<button (click)="addItem(name.value)">Add Item </button>

<br/>
<br/>

Items List:

<div *ngFor="let item of app.items">
  View Name: <span>{{item.name}}</span>
</div>

<br/>

Items List 2 with updates:

<div *ngFor="let item of app.items">
  Update Name: <input [(ngModel)]="item.name" />
</div>

</ng-container>

Is this expected behaviour? I was expecting that I would not see that change reflected in the 'view only' list.

Or is this just a case of me doing something I shouldn't be - I know I should really be dispatching that change via an action to the store like this:

Update Name: <input [ngModel]="item.name" (ngModelChange)="updateItem(item.name)" />

updateItem(value) {
   this.store.dispatch(new UpdateItemAction(value));
}

I'm testing this with

* ngxs: 3.0.1
* @angular/core: 6.0.0

See full sample repo here https://github.com/garthmason/ngxs

Thanks!


回答1:


It's not a bug, it's a feature ;)

When selecting a piece of the state it will in fact return the object that is the state.

Which means that if you change a property to something else the state will get updated.

What I would suggest when working with a form is that you make a copy of the data before you start changing it with ngModel.

when using reactive forms there is a function called patchValue which will do this. https://angular.io/guide/reactive-forms#patchvalue

When it comes to normal forms you will have to do it manually.

lodash comes with a function called cloneDeep which should help you https://lodash.com/docs#cloneDeep

var objects = [{ 'a': 1 }, { 'b': 2 }];

var deep = _.cloneDeep(objects);
console.log(deep[0] === objects[0]);
// => false


来源:https://stackoverflow.com/questions/50247260/binding-to-state-is-this-expected-behaviour

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!