NgRx中如何在前一个Action成功后调度后续Action?
最优解决方案:确保顺序执行且状态已更新
你对现有两个方案的分析非常准确——方案一不管请求成败都会触发第二个动作,方案二的并发执行可能导致状态还没更新就发起了第二个请求。针对你的需求,这里有两个更可靠的解决方案,都能满足「第一个请求成功、searchSuccess完成状态更新后再触发第二个请求」的要求:
方案三:在第一个Effect中按顺序分发动作(利用concatMap保证顺序)
既然问题出在mergeMap会并发分发多个动作,我们可以改用concatMap结合concat来保证动作的顺序执行。因为NgRx的reducer是同步执行的,只要searchSuccess动作先被分发并处理完成,状态就会立即更新,之后再分发第二个请求动作就不会有状态未就绪的问题:
[...] switchMap(([_, endpointGenerator, { id}]) => this.httpClient .get<ApiFirstEntitySearchSuccess>(`${this.apiBaseUrl}${endpointGenerator(id)}`, { headers: new HttpHeaders(this.httpHeadersConfig), params: {} }) .pipe( takeUntil( this.actions$.pipe( ofType(ApiFirstEntityActions.searchRequest), skip(1) ) ), concatMap((success) => // 先分发searchSuccess确保状态更新,再分发第二个请求动作 concat( of(ApiFirstEntityActions.searchSuccess({ success })), of(ApiSecondEntityActions.searchRequest()) ) ), catchError((failure) => of(ApiFirstEntityActions.searchFailure({ failure }))) ) ), [...]
这里的核心是concat操作符,它会等待第一个动作的分发与状态更新完成后,再执行第二个动作的分发,从根源上避免了并发导致的状态未就绪问题。
方案四:拆分到独立Effect监听searchSuccess动作(更符合NgRx单一职责)
如果想让代码职责更清晰,我们可以拆分出单独的Effect,专门监听ApiFirstEntityActions.searchSuccess动作——这个动作只有在第一个请求成功、状态更新完成后才会被触发,此时直接发起第二个请求就完全不用担心状态问题:
// 第一个Effect:仅负责第一个请求的生命周期与状态更新 @Effect() firstEntitySearch$ = this.actions$.pipe( ofType(ApiFirstEntityActions.searchRequest), switchMap(({ id, endpointGenerator }) => this.httpClient .get<ApiFirstEntitySearchSuccess>(`${this.apiBaseUrl}${endpointGenerator(id)}`, { headers: new HttpHeaders(this.httpHeadersConfig) }) .pipe( takeUntil(this.actions$.pipe(ofType(ApiFirstEntityActions.searchRequest), skip(1))), map(success => ApiFirstEntityActions.searchSuccess({ success })), catchError(failure => of(ApiFirstEntityActions.searchFailure({ failure }))) ) ) ); // 第二个Effect:监听第一个请求的成功动作,触发后续请求 @Effect() secondEntitySearchAfterFirstSuccess$ = this.actions$.pipe( ofType(ApiFirstEntityActions.searchSuccess), map(() => ApiSecondEntityActions.searchRequest()) );
这个方案的优势在于:
- 每个Effect职责单一,第一个Effect只处理第一个请求的发起、成功/失败处理,第二个Effect只负责后续触发逻辑
- 完全规避了并发风险,因为
searchSuccess动作的触发本身就代表状态已经完成更新,此时第二个请求获取ID不会有任何问题
为什么这两个方案可行?
NgRx中,动作的分发与reducer的执行是同步的:当你分发searchSuccess动作后,reducer会立即完成状态更新,状态的变更会同步生效。所以无论是方案三中的顺序分发,还是方案四中监听searchSuccess动作,都能确保第二个请求触发时,状态已经包含了第一个请求返回的ID。
内容的提问来源于stack exchange,提问作者KevinTale
相关产品推荐
相关产品推荐

