我正在尝试设置loginEpic,这是当用户登录时发生的。这就是逻辑流应该如何工作的方式:
史诗应该从LOGIN_REQUEST动作开始。一旦成功完成登录承诺,应该使用SYNC_USER_REQUEST操作获取用户信息(这基本上是另一个史诗,因为这在最初进入站点获取用户信息或重定向登录时也会被调用)。一旦成功完成(承诺和成功/失败调用在syncUserEpic中被处理),SYNC_USER_SUCCESS应该在loginEpic中被捕获,LOGIN_SUCCESS应该与重定向用户到起始页面的push操作一起被调用。
到目前为止,这就是我所拥有的:
const loginEpic: Types.RootEpic = (action$) =>
action$.ofType("LOGIN_REQUEST").pipe(
switchMap(({ payload }) =>
from(membershipService.login(payload.username, payload.password)).pipe(
switchMap((response) => [
syncUser.request(),
action$.ofType("SYNC_USER_SUCCESS").pipe( // I think this is the problem
filter(isActionOf(syncUser.success)),
map(r => login.success(response))
)
]),
takeUntil(action$.ofType(["LOGOUT_REQUEST", "LOGIN_CANCEL"])),
catchError(error => of(login.failure(error))),
endWith(push("/"))
)
)
)但我得到了
动作必须是普通的对象。使用自定义中间件进行异步操作。
我还取消了LOGIN_REQUEST/SYNC_USER_REQUEST的LOGOUT_REQUEST或LOGIN_CANCEL操作,也处理了登录错误(我不确定这里是否也应该处理同步用户错误)
发布于 2019-09-13 09:31:15
我设法以这样的方式实现了它:
const loginEpic: Types.RootEpic = (action$) =>
action$.pipe(
filter(isActionOf(login.request)),
switchMap(({ payload }) =>
race(
from(membershipService.login(payload.username, payload.password)).pipe(
mergeMap((token) =>
from(membershipService.getUser()).pipe(
mergeMap((user) => [syncUser.success(user), login.success(token)]),
catchError(error => {
// user fetch failed, tell login that user is responsible
return of(login.failure(new BaseError("6010", "User sync failed.")));
})
)
),
catchError(error => of(login.failure(error))),
),
action$.pipe(
filter(isActionOf(logout.request)),
map(() => login.cancel()),
take(1)
)
)
)
)根据它的工作原理,race实际上是在运行整个第一个块(不仅仅是外部membershipService.login,还有logout.request操作)。我没有意识到这一点,我想我需要membershipService.getUser的另一个race条件,因为我需要的是logout.request终止整个进程(即使login成功并且进程处于获取用户的中间)。就我所能测试的情况而言,它正如期而至。
如果有人有任何想法,改进,修正,或反模式的观察,请告诉我。
https://stackoverflow.com/questions/57913178
复制相似问题