发送响应取消的操作
Dispatch an action in response to cancellation
我从 redux-observable 文档中的 cancellation recipe 开始,想对其进行一些扩展。
基本上我有一个场景,在取消被触发后,使用 takeUntil
我想分派另一个动作来清理等
这是我到目前为止想出的:https://jsbin.com/zemenu/195/edit?js,output
开始 "Fetch User Info" 然后点击取消。我希望它按以下顺序执行操作:
- USER/FETCH
- REQUEST/STARTED
- USER/CANCELLED
- REQUEST/CANCELLED
这按照我现在设置的方式工作。但是,我必须依靠将 dispatch
传递给 requestSequence
函数,然后在 finally
中触发它。有没有一种更简洁的方法可以只使用可观察的运算符来做到这一点?因此,当 USER.CANCELLED
被触发时,一些最终操作会映射到 requestSequence
可观察对象内部。
Redux 记录器已启用,因此请检查控制台以了解所有操作。
而不是使用 .takeUntil()
,听起来您想使用 .race()
,这个名字非常恰当。哪个流先发出,谁就赢了!另一个未订阅。
您需要对某些内容进行一些重组才能按需使用它。您希望将您立即发出的第一个操作(您的 request.onStart(meta)
)与 ajax 请求 Observable.fromPromise(apiCall(...args))
分开。然后你想直接在 ajax 和取消之间进行比赛,所以你需要传入 action$
ActionsObservable,因为你在 helper 中拥有所有这些。
https://jsbin.com/suvaka/edit?js,output
function requestSequence(apiCall, args, meta, action$) {
return Observable.of(request.onStart(meta))
.concat(
Observable.fromPromise(apiCall(...args))
.map((payload) => request.onSuccess(payload, meta))
.catch((e) => Observable.of(request.onError(e, meta)))
.race(
action$.ofType(USER.CANCELLED)
.map(() => request.onCancel(meta))
)
);
}
const fetchUserEpic = (action$, store) =>
action$.ofType(USER.FETCH)
.mergeMap(action =>
requestSequence(
userRequest,
[`/api/users/${action.payload}`],
{ activity: USER.FETCH, path: 'user' },
action$
)
);
旁注:小心过早的抽象,比如制作那些类型的助手。尽管您可能会在某些 epics 中重复某些内容,但我发现将其抽象化会使以后更难理解,尤其是当代码不是由其他人编写且不是 Rx 大师时。当然,只有您自己知道这条建议是否适用于您和您的代码库。
对我来说主要的困惑点是你必须传递给 requestSequence
的所有参数,这对很多人第一次遇到它时很难理解。如果你发现你的 epics 非常非常普遍地做完全相同的事情并且你想重用,也许抽象整个史诗会更清楚,并在下面创建 API 实用程序,如 userRequest
你可以独立测试。
(未经测试,基本是伪代码)
const createApiEpic = options =>
action$ =>
action$.ofType(options.on)
.mergeMap(action =>
Observable.of(request.onStart(meta))
.concat(
options.effect(action.payload)
.map(payload => request.onSuccess(payload, meta))
.catch(e => Observable.of(request.onError(e, meta)))
.race(
action$.ofType(options.cancel)
.map(() => request.onCancel(meta))
)
)
);
const userRequest = id =>
Observable.ajax.getJSON(`/api/users/${id}`);
const fetchUserEpic = createApiEpic({
on: USER.FETCH,
effect: userRequest
cancel: USER.CANCELLED
});
我从 redux-observable 文档中的 cancellation recipe 开始,想对其进行一些扩展。
基本上我有一个场景,在取消被触发后,使用 takeUntil
我想分派另一个动作来清理等
这是我到目前为止想出的:https://jsbin.com/zemenu/195/edit?js,output
开始 "Fetch User Info" 然后点击取消。我希望它按以下顺序执行操作:
- USER/FETCH
- REQUEST/STARTED
- USER/CANCELLED
- REQUEST/CANCELLED
这按照我现在设置的方式工作。但是,我必须依靠将 dispatch
传递给 requestSequence
函数,然后在 finally
中触发它。有没有一种更简洁的方法可以只使用可观察的运算符来做到这一点?因此,当 USER.CANCELLED
被触发时,一些最终操作会映射到 requestSequence
可观察对象内部。
Redux 记录器已启用,因此请检查控制台以了解所有操作。
而不是使用 .takeUntil()
,听起来您想使用 .race()
,这个名字非常恰当。哪个流先发出,谁就赢了!另一个未订阅。
您需要对某些内容进行一些重组才能按需使用它。您希望将您立即发出的第一个操作(您的 request.onStart(meta)
)与 ajax 请求 Observable.fromPromise(apiCall(...args))
分开。然后你想直接在 ajax 和取消之间进行比赛,所以你需要传入 action$
ActionsObservable,因为你在 helper 中拥有所有这些。
https://jsbin.com/suvaka/edit?js,output
function requestSequence(apiCall, args, meta, action$) {
return Observable.of(request.onStart(meta))
.concat(
Observable.fromPromise(apiCall(...args))
.map((payload) => request.onSuccess(payload, meta))
.catch((e) => Observable.of(request.onError(e, meta)))
.race(
action$.ofType(USER.CANCELLED)
.map(() => request.onCancel(meta))
)
);
}
const fetchUserEpic = (action$, store) =>
action$.ofType(USER.FETCH)
.mergeMap(action =>
requestSequence(
userRequest,
[`/api/users/${action.payload}`],
{ activity: USER.FETCH, path: 'user' },
action$
)
);
旁注:小心过早的抽象,比如制作那些类型的助手。尽管您可能会在某些 epics 中重复某些内容,但我发现将其抽象化会使以后更难理解,尤其是当代码不是由其他人编写且不是 Rx 大师时。当然,只有您自己知道这条建议是否适用于您和您的代码库。
对我来说主要的困惑点是你必须传递给 requestSequence
的所有参数,这对很多人第一次遇到它时很难理解。如果你发现你的 epics 非常非常普遍地做完全相同的事情并且你想重用,也许抽象整个史诗会更清楚,并在下面创建 API 实用程序,如 userRequest
你可以独立测试。
(未经测试,基本是伪代码)
const createApiEpic = options =>
action$ =>
action$.ofType(options.on)
.mergeMap(action =>
Observable.of(request.onStart(meta))
.concat(
options.effect(action.payload)
.map(payload => request.onSuccess(payload, meta))
.catch(e => Observable.of(request.onError(e, meta)))
.race(
action$.ofType(options.cancel)
.map(() => request.onCancel(meta))
)
)
);
const userRequest = id =>
Observable.ajax.getJSON(`/api/users/${id}`);
const fetchUserEpic = createApiEpic({
on: USER.FETCH,
effect: userRequest
cancel: USER.CANCELLED
});