javascript - 在 redux-observable 中完成一些异步操作后,如何对 redux 操作进行排序?
问题描述
语境
对于需要加载的不同页面元素,我有很多形式的操作:LOAD_XYZ
, LOAD_XYZ_FAIL
, 。LOAD_XYZ_SUCCESS
我经常希望react-router
在某些项目加载后执行重定向(),但由于redux-observable
不返回承诺,我无法在我的组件中执行重定向 - 但我必须使用redux
and push('...')
from来执行此操作react-router-redux
。
不幸的是,这导致了很多重复,就像我拥有的一样,LOAD_XYZ
以及LOAD_XYZ_REDIRECT_TO
相同动作的版本,以及每个动作的两个史诗。
这开始让人感到浪费并且冗余过多
const fetchUserEpic = action$ =>
action$.ofType(FETCH_USER)
.mergeMap(action =>
ajax.getJSON(`https://api.github.com/users/${action.payload}`)
.map(response => fetchUserFulfilled(response))
);
const fetchUserAndRedirectEpic = action$ =>
action$.ofType(FETCH_USER_AND_REDIRECT)
.mergeMap(action =>
ajax.getJSON(`https://api.github.com/users/${action.payload}`)
.concatMap(response => [fetchUserFulfilled(response), push(action.redirectTo)])
);
问题
是否有某种模式/方法,我可以在某种异步请求完成后对要调度的操作进行排序,以避免冗余和必须实现同一史诗的多个版本。
例如,我希望有一个单独的REDIRECT_TO
操作,我可以在加载项目后对其进行排序。
像这些(想象的)解决方案:
dispatch(fetchUser(...)).then(redirectTo("..."))
dispatchSequence(fetchUser(...), redirectTo("..."))
我知道redux-thunk
可以做到这一点,但是我错过了所有 rxjs 运算符。
解决方案
我可能正在深入危险的地方,但我确实找到了一种方法来做到这一点。
首先,我们制作一个中间件,它将作为元数据添加到 action 中的完成 observable。
import { Subject } from "rxjs";
export const AddListenerMiddleware = store => next => action => {
const forkedAction = Object.assign({}, action, { meta: { listener: new Subject()}});
next(forkedAction);
return forkedAction.meta.listener.asObservable();
};
由于这是 aSubject
我们可以调用next
它来发出一些值。创建一个notify
助手允许我们通知任何订阅者操作何时完成(加上传递数据)。
// notify doesn't consume but just emits on the completion observable
const notify = (action, fn) => source =>
Observable.create(subscriber =>
source.subscribe(emmission => {
if (action.meta && action.meta.listener) {
action.meta.listener.next(fn(emmission));
}
subscriber.next(emmission);
})
);
const fetchUserEpic = action$ =>
action$.ofType(FETCH_USER)
.mergeMap(action =>
ajax.getJSON(`https://api.github.com/users/${action.payload}`)
.map(response => fetchUserFulfilled(response))
.pipe(notify(action, response => response.data))
);
现在我们的 dispatch 返回一个 observable,我们可以在它上面进行标准的 rxjs 操作。所以这最终成为可能:
dispatch(fetchUser(...))
.subscribe(({id}) => dispatch(redirectTo("/" + id)))
免责声明:使用风险自负!
推荐阅读
- swift - 如何快速比较两种不同的日期格式
- c++ - 需要限制“检测特征()”的角度上限,而不仅仅是下限。应该很容易?
- java-8 - Java8 - 独立代码的异步执行
- macos - 列出 macOS 上所有已加载/已卸载或同时启动的代理
- javascript - 我有一个对象数组,每个对象内部都有一个称为分数的键,我需要找到每个分数的总和并将其推送到一个数组中
- ruby-on-rails - 如何使用 s3-select 获取 s3 json 文件中子对象的计数?
- python - 无法将 django 静态文件保存到 AWS S3
- mysql - 不可接受 在此服务器上找不到所请求资源的适当表示。此错误是由 Mod_Security 生成的
- sql - 如何获取 Hive 中字符串使用的文本字节?
- java - 这段代码是某种命令模式吗?