gpt4 book ai didi

reactjs - 在react-router onEnter hooks中延迟添加新的史诗是一种有效的做法吗?

转载 作者:行者123 更新时间:2023-12-03 13:42:25 26 4
gpt4 key购买 nike

当将redux-observable与react-router一起使用时,按照文档here中的说明异步添加新的史诗是否有意义?在路由更改期间,在react-router的onEnter钩子(Hook)内部?

./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
};

...routes/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. 如果我想通过 console.log 记录哪些史诗已添加到 rootEpic 中,我该怎么做?

<小时/>

针对@JayPhelps进行编辑

我可以要求澄清一些问题吗?

  1. registerEpic fn 效果很好。我一直在使用 .distinct() 运算符来解决重复的史诗注册问题,如下所示:

    export const Epid$ = newBehaviorSubject(combineEpics(epic1, Epic2)).distinct()

这是处理惰性史诗注册的同样有效/好的方法吗?如果不是,您能解释一下原因吗?

  • 我正在使用 create-react-app,它具有 require.ensure 以及 ES6 导入(它们是不同的导入方式,对吧?),基本上,我复制粘贴 react-router's huge-apps example其中有 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 中设置 token 变量来以一种非常愚蠢且可能错误的方式进行操作,但它所做的只是调用一个函数注册新的史诗:

    './../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。 (我发现 your login example on github 所以它可能看起来很熟悉)。这是正确的吗,还是我完全没有根据?我知道 .concat() 是同步的,并且我知道 redux 是同步的 - 我不确定 registerEpics() 是否是同步的,但使用 reducer 注册 Epiks 似乎可以正常工作 - 这是否意味着 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
    }))
    );

    最佳答案

    In this case, would epic3 get added again to the rootEpic every time we navigate to /some-path?

    如果你正在使用react-router并进行代码分割,你实际上会想在你的 getComponent 中添加必要的史诗。钩子(Hook),不是 onEnter钩。这是因为getComponent hook 允许异步加载该路由所需的资源,不仅是组件,还包括任何史诗、 reducer 等。如果您使用 require.ensure() ,这告诉 webpack 将这些项目分割成一个单独的包,这样它们就不会包含在原始条目中 - 所以不要将这些文件导入到其他任何地方,否则你会否定这一点!

    粗略地看,这是一个可能看起来像这样的示例:

    路线/SomePath/index.js

    import { registerEpic } from 'where/ever/this/is/epics/index.js';

    export default {
    path: 'some-path',

    getComponent(location, done) {
    require.ensure(['./components/SomePath', 'path/to/epics/epic3'], require => {
    // this is where you register epics, reducers, etc
    // that are part of this separate bundle
    const epic = require('path/to/epics/epic3').epic3;
    registerEpic(epic);

    done(null, require('./components/SomePath'));
    });
    }
    };

    where/ever/this/is/epics/index.js

    import { BehaviorSubject } from 'rxjs/BehaviorSubject';
    import { combineEpics } from 'redux-observable';

    import { epic1 } from './epic1';
    import { epic2 } from './epic2';

    const epicRegistry = [epic1, epic2];
    const epic$ = new BehaviorSubject(combineEpics(...epicRegistry));

    export const registerEpic = (epic) => {
    // don't add an epic that is already registered/running
    if (epicRegistry.indexOf(epic) === -1) {
    epicRegistry.push(epic);
    epic$.next(epic);
    }
    };

    // your root epic needs to use `mergeMap` on the epic$ so any
    // new epics are composed with the others
    export const rootEpic = (action$, store) =>
    epic$.mergeMap(epic =>
    epic(action$, store)
    );

    我创建了一个注册功能,确保您不会添加已经添加的史诗; React-router 将调用 getComponent 每次您进入该路线,因此这一点很重要,这样您就不会拥有同一史诗的两个正在运行的实例。

    但是请注意,当涉及 require('path/to/epics/epic3').epic3 之类的事情时,我的代码做出了一些可能是错误的假设。 。你的epic3实际上是作为命名属性导出的吗?我想是这样,但我注意到你正在这样做done(null, require('./components/SomePath'))我的直觉告诉我,如果您使用 export default 导出该组件,则可能无法正常工作带有 ES2015/ES6 模块。如果这是真的,它实际上可以在 require('./components/SomePath').default 找到。 --注意.default !因此,虽然我的代码是总体思路,但您应该特别注意需要路径、导出属性等。您说它似乎有效,所以也许您的设置不同(或者我只是错了呵呵)

    <小时/>
    1. If I wanted to console.log which epics have been added into the rootEpic, how would I do that?

    最简单的方法就是登录 registerEpic效用:

    export const registerEpic = (epic) => {
    // don't add an epic that is already registered/running
    if (epicRegistry.indexOf(epic) === -1) {
    epicRegistry.push(epic);
    console.log(`new epic added: ${epic.name}`);
    epic$.next(epic);
    }
    };

    但是您也可以使用 RxJS .do() 更具体地做到这一点您的 epic$ 上的运算符(operator)主题:

    export const rootEpic = (action$, store) =>
    epic$
    .do(epic => console.log(`new epic added: ${epic.name || '<anonymous>'}`))
    .mergeMap(epic =>
    epic(action$, store)
    );

    但是,这将记录 <anonymous>第一次,因为第一个出现的结果是 combineEpics(...epicRegistry)它将多个史诗组合成一个匿名史诗。

    关于reactjs - 在react-router onEnter hooks中延迟添加新的史诗是一种有效的做法吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40202074/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com