将 redux-observable 与 react-router 一起使用时,在路由更改期间按照文档中的说明在 react-router 的 onEnter 挂钩中异步添加新史诗是否有意义?
./epics/index.js
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import { combineEpics } from 'redux-observable';
import { epic1 } from './epic1'
import { epic2 } from './epic2'
export const epic$ = new BehaviorSubject(combineEpics(epic1, epic2));
export const rootEpic = (action$, store) =>
epic$.mergeMap(epic =>
epic(action$, store)
);
export {
rootEpic
};
...路线/SomePath/index.js
import { epic$ } from './../../../../epics/index'
import { epic3 } from './../../../../epics/epic3'
module.exports = {
path: 'some-path',
getComponent( location, cb ) {
require.ensure( [], ( require ) => {
cb( null, require( './components/SomePath' ) )
} )
},
onEnter() {
epic$.next(epic3)
}
}
Rxjs 和 redux-observable 非常新。这似乎可行,但想知道: 1. 在这种情况下,每次我们导航到 /some-path 时,epic3 会再次添加到 rootEpic 吗?2. 如果我想控制台记录哪些史诗已添加到 rootEpic 中,我该怎么做?
编辑以回应@JayPhelps
我可以要求澄清几点吗?
registerEpic fn 效果很好。我一直在使用 .distinct() 运算符来解决重复的史诗注册问题,如下所示:
export const epic$ = new BehaviorSubject(combineEpics(epic1, epic2)).distinct()
这是处理惰性史诗注册的同样有效/好的方法吗?如果不是,您能解释一下原因吗?
- 我正在使用具有 require.ensure 和 ES6 导入的 create-react-app(它们是不同的导入方式,对吗?),基本上,我复制粘贴了react-router 的巨大应用程序示例,其中包含
require.ensure
代码,但无处不在否则,我在文件顶部使用 import 语句。
因此,在顶部导入史诗和 registerEpic fn 似乎可行,而将路径放在 require.ensure 第一个参数中似乎也可行。如果我使用 require.ensure AND import 语句,它会变得混乱吗?如果我使用 require.ensure 来加载路由需要的所有内容,这是否意味着我删除了该路由组件的嵌套(无路由)组件内的所有导入语句?
import { epic3 } from './../../epics/epic3'
import { epic4 } from './../../epics/epic4'
import { registerEpic } from './../../epics/index'
module.exports = {
path: 'my-path',
getComponent( location, done ) {
require.ensure( [], ( require ) => {
registerEpic(addYoutubeEpic)
registerEpic(linkYourSiteEpic)
done( null, require( './components/Edit' ) )
} )
}
}
关于在 'getComponent' fn 中注册史诗以进行异步加载 - 我认为实际上需要在此处进行同步加载,以便在注册史诗之前不会渲染路由的组件。如果用户尝试在路线上做一些事情,比如获取一些详细信息或提交表单,需要注册史诗,而史诗尚未注册,会发生什么?
在 react-router module.export 声明之外还有其他地方适合懒惰地注册史诗吗?由于我项目中的许多路由不需要登录,因此登录并不总是会触发路由更改。但是,在用户登录后应该注册一堆史诗。目前,我通过在我的 authReducer 中设置一个令牌变量以一种非常愚蠢且可能错误的方式来做这件事,但它所做的只是调用一个函数注册新的史诗:
'./../reducers/authReducer.js' import { greatEpic } from './../epics/fetchFollowListEpic' import { usefulEpic } from './../epics/fetchMyCollectionsEpic' // and a few more import { registerEpic } from './../epics/index' const addEpics = () => { registerEpic(greatEpic) registerEpic(usefulEpic) ...etc } export default function reducer( state = { loggingIn: false, loggedIn: false, error: '', }, action ) { switch ( action.type ) { case "LOGIN_SEQUENCE_DONE": { return { ...state, aid: setAuthToken(action.payload), loginFailed: false, addEpics: addEpics(), } }
我想 loginEpic 将是注册史诗的更好地方,而不是 reducer。(我在 github 上找到了您的登录示例,因此它可能看起来很熟悉)。这是正确的,还是我完全偏离了基地?我知道 .concat() 是同步的,而且我知道 redux 是同步的——我不确定 registerEpics() 是否同步,但是使用 reducer 注册史诗似乎可以正常工作——这是否意味着 registerEpics 是同步的?还是仅仅意味着事情发展得如此之快以至于无关紧要?还是仅由于我对 import 语句以及 webpack 如何处理我必须研究更多的代码拆分存在一些基本的误解而起作用?
./../epics/loginEpic
export const loginEpic = action$ =>
action$.ofType("LOGIN")
.mergeMap(action =>
Observable.fromPromise(axios.post('webapi/login', action.payload))
.flatMap(payload =>
// Concat multiple observables so they fire sequentially
Observable.concat(
// after LOGIN_FULILLED
Observable.of({ type: "LOGIN_FULFILLED", payload: payload.data.aid }),
// ****This is where I think I should be registering the epics right after logging in. "ANOTHER_ACTION" below depends upon one of these epics****
Observable.of({type: "ANOTHER_ACTION", payload: 'webapi/following'}),
Observable.of({type: "LOGIN_SEQUENCE_DONE"}),
)
)
.startWith({ type: "LOGIN_PENDING" })
.takeUntil(action$.ofType("LOGIN_CANCELLED"))
.catch(error => Observable.of({
type: "LOGIN_REJECTED",
payload: error,
error: true
}))
);