Data Flow(数据流)

Redux状态流转中,我们大概了解了Redux中Store、Action、Reducer的概念。下面将详细分析下它们之间的数据流关系。

一、数据发送与接收

当数据变化的时候,我们需要发送Action(如:LoadAction、UpdateAction),产生一个信号,由reducer去处理这个Action。

当数据请求成功的场合,我们需要从store里面,通过selector将数据拉回来进行UI更新。

  • facade内容如下:

    • 发送信号Action的dispatch方法

    • 通pipe将select中获取到的数据转化为Observable

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// content-hrmanager.facade.ts

// 发送action
dispatch(action: Action) {
  this.store.dispatch(action);
}

// 数据接收
loaded$ = this.store.pipe(
  select(ContentHrmanagerSelectors.getContentHrmanagerLoaded)
);
  • selector内容如下:

    • 创建从entities和state中取得数据的selector方法
1
2
3
4
5
6
7
// content-hrmanager.selectors.ts

export const getSelected = createSelector(
  getContentHrmanagerEntities,
  getSelectedId,
  (entities, selectedId) => selectedId && entities[selectedId]
);

二、API交互

当接收到加载、增加、更新等Actions之后,通过下面方式,筛选具体action的类型,通过service和api进行交互。

当请求成功和请求失败后,发送成功和失败的action。当reducer接收到action之后,产生新状态存储到store中。

  • effect内容如下:

    • 接收Action,调用Service和API进行交互

    • 处理结束后,发送成功/失败Action,给reducer处理

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
  * 通过id查询用户数据
  */
loadContentHrmanagerById$ = createEffect(() =>
  this.dataPersistence.fetch(
    ContentHrmanagerActions.loadContentHrmanagerById, {
      run: (action: any) => {
        // 取出参数id,查询用户数据
        return this.hrManagerService.get(action.id).pipe(
          // 正常,发出成功action
          map(data => (ContentHrmanagerActions.loadContentHrmanagerByIdSuccess({ id: action.id, contentHrmanager: data}))),
          // 异常,发出失败action
          catchError(err => of(ContentHrmanagerActions.loadContentHrmanagerFailure({ error: (err as HttpErrorResponse).message }))
          )
        );
      },
      onError: (action, error) => {
        console.error('Error', error);
        return ContentHrmanagerActions.loadContentHrmanagerFailure({ error });
      }
    }
  )
)

三、产生新的状态

当reducer接收到跟画面UI相关的Action,如XXXSuccess、XXXError等,产生新的状态,存储在Store。

  • reducer的内容如下:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
// 无论成功/失败都会产生新状态, 并存储于store中 

on(
  ContentHrmanagerActions.loadContentHrmanagerSuccess,
  (state, { contentHrmanager }) =>
    contentHrmanagerAdapter.setAll(contentHrmanager, {
      ...state,
      loaded: true,
    })
),
on(
  ContentHrmanagerActions.loadContentHrmanagerFailure,
  (state, { error }) => ({ ...state, error })
)

四、更新UI组件

当上面几步执行完成后,我们通过selector将值取出来,并更新UI组件。

通过下面的方式,可以取得更新成功/失败的处理结果。

  • 成功的场合
1
2
3
4
5
6
7
// ts

// 成功的场合, 并通过管道的方式将值取出来
this.user$ = this.hrManagerFacade.selectedContentHrmanager$;

// html
{{(user$ | async)?.id}}
  • 失败的场合
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// ts

// 通过在构造方法中注入action$,从action$过滤失败的action
constructor(private hrManagerFacade: ContentHrmanagerFacade, private action$: Actions) {
  // 从action$流中筛选错误的action
  this.action$.pipe(
    ofType(ContentHrmanagerActions.loadContentHrmanagerFailure)).subscribe(err => {
      console.log('err => ' + err.error);
    }
  )
}

完整流程