我现在已经尝试了几种方法来管理组件的表单状态。
对于这个例子,我将使用一个自定义组件,它可以从下拉列表中选择一个用户,并使用一个按钮添加它们,然后在表格行中显示每个用户。每行都有一个 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
索引并制作它比必要的更复杂。