我正在使用ngrx / store 1.5以及thunk中间件的应用程序,我正在尝试移动到ngrx / store 2.0和ngrx / effects。关于如何处理多个相关的动作和/或效果,我有几个问题。
我意识到"心态"对于thunks vs效果是不同的,我试图了解差异。我查看了可用的示例应用程序,并且找不到任何适合我尝试的内容,所以也许我仍然完全错误。
情景1
这是一个副作用,用于处理向服务器发出登录请求:
@Effect login$: any = this.updates$
.whenAction(LoginActions.LOGIN)
.map(toPayload)
.switchMap(payload =>
this.loginService.login(payload.user, payload.password)
.map(result => this.actions.loginSuccess(value))
.catch((error) => Observable.of(this.loginError(error)))
));
鉴于最初的副作用,那么"正确"或"建议"触发导航到"家庭"登录成功后的屏幕?这也可以概括为简单地触发一系列动作或操作。
我考虑过几个选项:
(a)登录成功触发的另一个效果,即触发后续动作以触发导航?
@Effect navigateHome$: any = this.updates$
.whenAction(LoginActions.LOGIN_SUCCEEDED)
.mapTo(this.actions.navigateHome());
(b)登录成功触发的另一个效果,即执行导航操作?
@Effect navigateHome$: any = this.updates$
.whenAction(LoginActions.LOGIN_SUCCEEDED)
.do(this.navigateHome())
.filter(() => false);
(c)将其他行动与初始登录效果发出的行动联系起来? (样本显然不太正确,但提出了想法)
@Effect login$: any = this.updates$
.whenAction(LoginActions.LOGIN)
.map(toPayload)
.switchMap(password => Observable.concat(
this.loginService.login(passcode)
.map(result => this.actions.loginSuccess(value))
.catch((error) => Observable.of(this.loginError(error))),
Observable.of(this.actions.navigateHome())
));
(d)其他?
场景2
考虑需要按顺序进行多个请求的情况,并且当每个请求开始时,我们想要更新"状态"以便可以向用户提供反馈。
沿着这些线的东西的例子:
multiphaseAction() {
return (dispatch) => {
dispatch(this.actions.updateStatus('Executing phase 1');
this.request1()
.flatMap(result => {
dispatch(this.actions.updateStatus('Executing phase 2');
return this.request2();
})
.flatMap(result => {
dispatch(this.actions.updateStatus('Executing phase 3');
return this.request3();
})
...
}
}
再次,"正确"或"建议"使用效果方法的方法呢?
这个我更加坚持,不知道除了以某种方式添加一些.do(this.store.dispatch(this.actions.updateStatus(...))
之外还能做些什么......
答案 0 :(得分:17)
导航方案的答案是你的回答
@Effect navigateHome$: any = this.updates$
.whenAction(LoginActions.LOGIN_SUCCEEDED)
.do(this.router.navigate('/home'))
.ignoreElements();
说明: 您对LOGIN_SUCCESS作出反应,并且因为路由器没有返回新动作,我们需要停止流的传播,我们通过过滤所有内容来实现。
如果您忘记过滤,路由器将返回undefined,这反过来将导致reducer减少未定义的值,这通常会在尝试读取操作的type
时导致空指针/ p>
另一种解决方法是使用https://github.com/ngrx/router-store
查看有关如何将路由器商店添加到您的应用的文档。
现在看起来效果相同。
import { go } from '@ngrx/router-store';
@Effect navigateHome$: any = this.updates$
.whenAction(LoginActions.LOGIN_SUCCEEDED)
.map(() => go(['/home']));
go
操作将调度路由器减速器将接收的路由器操作并触发路由更改。
答案 1 :(得分:2)
情景1
考虑navigateHome
是否应该改变状态。此外,是否从其他地方调度此navigateHome
操作以实现相同的操作。如果是这样,返回一个动作是要走的路。因此,选项A。
在某些情况下,选项B可能更有意义。如果navigateHome
仅更改路线,则可能值得考虑。
旁注:您可以在此使用ignoreElements代替filter(() => false)
。
场景2
我建议将你的行为链接在多个效果中,并通过修改每个动作的reducer中的状态来提供反馈。
例如:
@Effect() trigger$: Observable<Action> = this.updates$
.whenAction(Actions.TRIGGER)
.do(() => console.log("start doing something here"))
.mapTo(Actions.PHASE1);
@Effect() phase1$: Observable<Action> = this.updates$
.whenAction(Actions.PHASE1)
.do(() => console.log("phase 1"))
.mapTo(Actions.PHASE2);
@Effect() phase2$: Observable<Action> = this.updates$
.whenAction(Actions.PHASE2)
.do(() => console.log("phase 2"))
.ignoreElements();
通过修改状态提供反馈:
function reducer(state = initialState, action: Action): SomeState {
switch (action.type) {
case Actions.TRIGGER: {
return Object.assign({}, state, {
triggered: true
});
}
case Actions.PHASE1: {
return Object.assign({}, state, {
phase1: true
});
}
case Actions.PHASE2: {
return Object.assign({}, state, {
phase1: false,
phase2: true
});
}
// ...
}
}
答案 2 :(得分:0)
情景1
选项A&amp;我认为B都很好,但也许选项A对导航来说有点太多了!如果您认为导航是此副作用的一部分,您也可以直接在LoginActions.LOGIN
中使用路由器。
场景2
链接@Effects
没有错。
调度触发效果的动作(SET_1_REQUEST)A。效果A返回一个动作(SET_1_SUCCESS),由你的减速器拾取(现在你可以向用户显示该状态)并且它会被效果B拾取。
希望这是有道理的。
答案 3 :(得分:-1)
我也在学习这些东西。
如果你在链中的第一个完成时派遣到减速器怎么办?
这样的事情:
const myReducer = (state,action:Action) => {
switch action.type {
case : "my_first_step" : runfirststep(action.payload);
case : "my_second_step": runsecondstep(action.payload);
....
function runfirststep(data) {
...
//bunch of stuff to do,
//update something to display
store.dispatch('my_second_step');
}
等
ngrx示例在效果文件中执行此操作。当添加或更新时,他们可能会调用UPDATE_COMPLETE或类似的东西,因此可以进行一些通知。
我正在慢慢地了解减速器最终会在一个中等复杂的应用程序中占多大。