有没有办法在 RxJS / Redux-observable 中连接非 Redux 操作?

Is there a way to concat non-Redux actions in RxJS / Redux-observable?

成功登录后,我试图在获取用户配置之前将令牌存储在本地存储中。目前我只是在 mergeMap 中存储令牌,然后在 return 语句中获取配置。但是,我很确定有一种方法可以使用 concatconcatMap 依次调用存储和提取函数。

const authEpic = action$ =>
  action$.pipe(
    ofType('auth/AUTHENTICATION_SUCCESS'),
    mergeMap(action => {
      const { jwt } = action.payload;

      localStorage.setItem('token', jwt);

      return of({
        type: 'user/FETCH_CONFIG'
      });
    })
  );

以下是我的一次尝试,但未成功。虽然在这种情况下可能有其他方法从组件内部处理存储和获取,但我想知道这种模式在我遇到的其他情况下应该如何工作。

const authEpic = action$ =>
  action$.pipe(
    ofType('auth/AUTHENTICATION_SUCCESS'),
    mergeMap(action => {
      const { jwt } = action.payload;

      return concat(
        localStorage.setItem('token', jwt),
        of({ type: 'user/FETCH_CONFIG'})
      );
    })
  );

也许你可以尝试使用 last() 运算符,Concat 将在序列中的每个项目完成时发出,这就是它不起作用的原因。

  reuturn concat(
    of(localStorage.setItem('token', jwt)),
    of({ type: 'user/FETCH_CONFIG'})
  ).pipe(last());

我会采用你在问题中提到的第一种方法,因为 localStorage.setItem() 是同步的,因此在返回 FETCH_CONFIG 操作之前它总是被调用..

但是,如果您正在寻找替代方法,我建议您在返回 FETCH_CONFIG 操作之前使用 tap() 运算符分离逻辑。这也将确保按顺序调用这两个操作。

const authEpic = action$ =>
  action$.pipe(
    ofType('auth/AUTHENTICATION_SUCCESS'),
    tap(({ payload: { jwt } }) => {
      localStorage.setItem('token', jwt);
    }),
    mergeMap((action) => (of({
      type: 'user/FETCH_CONFIG'
    }))
  );

但是,如果你真的想使用 concat(),你需要将 localStorage.setItem() 动作包装在 of() 中以将其转换为可观察的,如 concat()要求所有成员都是可观察的,并且需要等待第一个订阅(localStorage.setItem())完成,然后第二个订阅(FETCH_CONFIG)才能开始。

const authEpic = action$ =>
  action$.pipe(
    ofType('auth/AUTHENTICATION_SUCCESS'),
    mergeMap(action => {
      const { jwt } = action.payload;

      return concat(
        of(localStorage.setItem('token', jwt)),
        of({ type: 'user/FETCH_CONFIG'})
      );
    }),
  );

concat 用于按照之前完成的顺序执行 observables。

检查来自 learnrx.io

的文档

You can think of concat like a line at an ATM, the next transaction (subscription) cannot start until the previous completes!

在您的示例中,我认为您不需要任何这些运算符,因为您没有在流程中执行任何异步操作。

您可以简单地使用以下代码更改您的代码:

action$.pipe(
  ofType('auth/AUTHENTICATION_SUCCESS'),
  tap(action => localStorage.setItem('token', action.payload)),
  mapTo({ type: 'user/FETCH_CONFIG'})
);