在 redux-observable 中完成某些异步操作后,如何对 redux 操作进行排序?
How can I sequence redux actions after some async action completed in redux-observable?
上下文
我有很多形式的操作:LOAD_XYZ
、LOAD_XYZ_FAIL
、LOAD_XYZ_SUCCESS
用于需要加载的不同页面元素。
我经常希望在某些项目加载后执行重定向 (react-router
),但由于 redux-observable
没有 return 我无法在我的组件中执行重定向的承诺 -但是我必须使用 react-router-redux
中的 redux
和 push('...')
来完成它。
不幸的是,这导致了很多重复,因为我有相同操作的 LOAD_XYZ
和 LOAD_XYZ_REDIRECT_TO
版本,每个版本还有两个 epics。
这开始让人觉得浪费且冗余太多
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)])
);
问题
是否有某种 pattern/approach 我可以在某种异步请求完成后对要分派的操作进行排序,以避免冗余和必须实现同一史诗的多个版本。
例如,我希望有一个单独的 REDIRECT_TO
操作,我可以在项目加载后对其进行排序。
类似这些(想象中的)解决方案:
dispatch(fetchUser(...)).then(redirectTo("..."))
dispatchSequence(fetchUser(...), redirectTo("..."))
我知道 redux-thunk
可以做到这一点,但后来我错过了所有 rxjs 运算符。
我可能正在深入危险地带,但我确实找到了方法。
首先我们制作一个中间件,它将作为 元数据 添加一个完成可观察到的动作。
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();
};
因为这是一个 Subject
我们可以调用 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 returns 一个 observable,我们可以在其上执行标准的 rxjs 操作。所以这最终成为可能:
dispatch(fetchUser(...))
.subscribe(({id}) => dispatch(redirectTo("/" + id)))
免责声明:使用风险自负!
上下文
我有很多形式的操作:LOAD_XYZ
、LOAD_XYZ_FAIL
、LOAD_XYZ_SUCCESS
用于需要加载的不同页面元素。
我经常希望在某些项目加载后执行重定向 (react-router
),但由于 redux-observable
没有 return 我无法在我的组件中执行重定向的承诺 -但是我必须使用 react-router-redux
中的 redux
和 push('...')
来完成它。
不幸的是,这导致了很多重复,因为我有相同操作的 LOAD_XYZ
和 LOAD_XYZ_REDIRECT_TO
版本,每个版本还有两个 epics。
这开始让人觉得浪费且冗余太多
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)])
);
问题
是否有某种 pattern/approach 我可以在某种异步请求完成后对要分派的操作进行排序,以避免冗余和必须实现同一史诗的多个版本。
例如,我希望有一个单独的 REDIRECT_TO
操作,我可以在项目加载后对其进行排序。
类似这些(想象中的)解决方案:
dispatch(fetchUser(...)).then(redirectTo("..."))
dispatchSequence(fetchUser(...), redirectTo("..."))
我知道 redux-thunk
可以做到这一点,但后来我错过了所有 rxjs 运算符。
我可能正在深入危险地带,但我确实找到了方法。
首先我们制作一个中间件,它将作为 元数据 添加一个完成可观察到的动作。
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();
};
因为这是一个 Subject
我们可以调用 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 returns 一个 observable,我们可以在其上执行标准的 rxjs 操作。所以这最终成为可能:
dispatch(fetchUser(...))
.subscribe(({id}) => dispatch(redirectTo("/" + id)))
免责声明:使用风险自负!