1

我现在已经尝试了几种方法来管理组件的表单状态。

对于这个例子,我将使用一个自定义组件,它可以从下拉列表中选择一个用户,并使用一个按钮添加它们,然后在表格行中显示每个用户。每行都有一个 startDate 和 endDate 以及一个用于清除日期的复选框。然后,发送表单以供提交。

大致是这样的container

<user-selector [users]="users$ | async"></user-selector>
<user-row *ngFor="let user of users$ | async">
  <input>{{user.startDate}}</input>
  <checkbox [value]="user.default"></checkbox>
  <input>{{user.endDate}}</divinput
</user-row>

方法一:

调度状态以存储以下单独的组件:

<user-selector>

  • SelectUser(user.id)
  • AddUser(user.id)

每个 ngFor user-row

  • SetUserDate(user.id, dateType, date)
  • SetUserDefault(user.id)

container

  • SaveUser(users)

现在我的状态总是同步的,我可以追溯任何以前的状态,并且可以使用 redux“时间旅行”来查看当我这样做时一切是否继续工作。

也许最混乱的是SetUserDate,因为它需要很多输入才能使其工作(dateType 是这样我不需要两个单独的操作) 其他的非常简单,reducers 确保数据被更新。最后,一个SaveUser接受当前users$状态并分派异步操作的操作。

方法二:

为每一行创建一个 formGroup:

const form = new FormGroup( users: new FormArray(generateGroups(users)));

generateGroups (users: User[]) => {
  users.forEach((user: User) => {
     return {
        startDate: new FormControl(user.startDate),
        defaultDate: new FormControl(false),
        endDate: new FormControl(user.endDate)
     };
  });
}

ngFor现在只需要通过 some 's将其塑造成与示例类似的 html 。

在这里我遇到了一些问题:

  • 设置复选框应直接将startDate&修改endDate''

form.valueChanges.subscribe本可以在开始和结束时分别听取更改,或者 combineLatest 可能会起作用。然后要么修改generateGroups函数以适应这种变化,要么users直接更新对象并generateGroups再次运行,或者执行patchValue.

我要修改组件上的状态的一个问题是,您基本上是在修改/更新状态,并避免修改原始状态(除非users对象已经是克隆,通过使用new User()模型或只是用{ ...user }或类似方法克隆它。

  • 添加用户

我可以做类似的事情:

addUser(user: User) {
  this.users.push(user);
}

以及用于删除用户的类似操作。但是在上面的示例中,我正在修改原始用户对象,如果该用户被绑定/引用到商店,那么这是有问题的,因此直接修改了商店。这将需要不同的解决方案:

addUser(user: User) {
  let newUsers = { ...this.users };
  newUsers.push(user);
  return newUsers;
}

那么return值也应该被处理,唯一明智的做法是不做后者,而是坚持前者,并确保this.users已经克隆了,避免改变状态。通过上述方法,哪里new Users(users)最有意义。

主要问题

我们最终要做的Approach 2就是做一个 reducer 做的事情,但是是在本地做的,并且没有任何事件/状态历史。

我想将所需的操作保持在最低限度,我对Approach 1. 这导致我采用第三种可能的方法:

方法 3

像第二种方法一样使用formGroups,然后用 听个别变化valueChanges,所以:

form.controls[0].defaultDate.controls.valueChanges.subscribe((changes) => {
   // Either dispatch action 
   this.store.dispatch(new SetUserDefault(this.user.id));
   // Or `patchValue`.
   form.controls[0].startDate.patchValue('');
   form.controls[0].endDate.patchValue('');
});

或者我可以订阅整个表单并找出发生了什么变化,以及何时以及如何采取何种行动(例如调度或patchValue)。(这听起来像是减速器的工作)

最后

考虑到这个表单至少有 4 种不同类型的类似表单的组件,在发送之前修改状态,这里最好做什么。

  • 根本不使用任何 redux 操作,除非在做的时候SaveUser,这意味着我在表单的初始状态之间没有时间线,直到最后。
  • 只使用 redux 意味着我必须做很多冗长的操作,并为每个操作制作 reducer。
  • 像最后一种方法一样使用这两种方法意味着formControls尽可能多地管理状态,但必须订阅每个单独的用户项,或者,我可以收听整个表单,但必须使用匹配的FormGroup索引并制作它比必要的更复杂。
4

0 回答 0