使用Lazy + Suspense反应预加载组件

时间:2018-11-11 20:21:31

标签: reactjs preload dynamic-import react-16

我目前正在使用带有Suspense和Lazy的React 16来代码拆分我的代码库。虽然我想预加载组件。

在下面的示例中,我有两条路线。 Demo挂载后,是否可以预载Prime?我试图在componentDidMount页面的Prime中创建另一个动态导入,但是React.lazy似乎并没有获得与下面的动态导入相同的文件。

import React, { lazy, Suspense } from 'react';
import { Switch, Route, withRouter } from 'react-router-dom';
import GlobalStyle from 'styles';

import Loading from 'common/Loading';
const Prime = lazy(() => import(/* webpackChunkName: "Prime" */'modules/Prime'));
const Demo = lazy(() => import(/* webpackChunkName: "Demo" */'modules/Demo'));

const App = () => (
  <main>
    <GlobalStyle />
    <Suspense fallback={<Loading>Loading...</Loading>}>
      <Switch>
        <Route path="/" component={Prime} exact />
        <Route path="/demo" component={Demo} />
      </Switch>
    </Suspense>
  </main>
);

export default withRouter(App);

因此,我尝试了不同的方法,例如在有和没有webpackChunkName的情况下,以及在componentDidMount中导入其他组件的不同方法,如下所示。在componentDidMount中导入文件的前两种方法导致Webpack错误,如下图底部所示。仅第三个继续执行,但在图像中生成文件2.[hash].js,仅在访问页面后加载,而不在componentDidMount

上加载

enter image description here

我在这里想念什么?

modules/Demo.jsx的代码:

import React from 'react';

import LogoIcon from 'vectors/logo.svg';
import PageLink from 'common/PageLink';
import Anchor from 'common/Anchor';
import CenteredSection from 'common/CenteredSection';

const Demo = () => (
  <CenteredSection variant="green">
    <LogoIcon />
    <PageLink to="/" variant="green">Go to home page</PageLink>
  </CenteredSection>
);

export default Demo;

2 个答案:

答案 0 :(得分:2)

这非常容易做到,我认为对于lazy()和Suspense在后台执行的操作存在误解。

React.lazy()唯一的期望是它采用一个函数,该函数返回一个使用默认组件解析的Promise。

React.lazy(() => Promise<{default: MyComponent}>)

因此,如果您要进行预加载,则要做的就是提前自己执行promise。

// So change this, which will NOT preload
import React from 'react';
const MyLazyComp = React.lazy(() => import('./path/to/component'));

/*********************************************/

// To this, which WILL preload
import React from 'react';

// kicks off immediately when the current file is imported
const componentPromise = import('./path/to/component');

// by the time this gets rendered, your component is probably already loaded
// Suspense still works exactly the same with this.
const MyLazyComp = React.lazy(() => componentPromise);

这是一个已知的签名,因此对于其他各种情况也很有用。例如,我有一堆依赖于动态加载google maps api的组件,我能够创建一个加载google maps api的函数,然后导入该组件。由于这个例子是切线的,所以我不详细介绍这个例子的内部原理,但是重点是我使自己成为一个执行一堆异步工作的函数,然后返回一个带有{default:Component}对象的Promise。

import React from 'react';
const MyLazyComp = React.lazy(() => importMapsComponent('./path/to/comp'));

答案 1 :(得分:1)

不确定这将有多大的帮助,但这是一个code sandbox可以正常工作(Demo由componentDidMount加载)。使用create-react-app作为配置,它是代码的相当简化的版本。也许您可以以此为起点,然后将其逐渐变形为更接近您的应用程序,以查看导致动态导入无法按预期工作的原因。