Skip to content

import()

在应用中引入代码分割的最佳方式是通过动态 import()。当 webpack 解析到该语法的时候会自动的开始代码分割。(Create-React-APP 和 Next.js 已支持该特性)

javascript
import('./math').then((math) => {
  console.log(math.add(16, 26));
});

React.lazy

React.lazy 函数能像渲染常规组件一样处理动态引入的组件。React.lazy 接受一个函数,这个函数需要动态调用 import()。它必须返回一个 Promise,该 Promise 需要 resolve 一个 default export 的 React 组件。

jsx
const OtherComponent = React.lazy(() => import('./OtherComponent'));

function MyComponent() {
  return (
    <div>
      <OtherComponent />
    </div>
  );
}

注:React.lazy 目前只支持默认导出(default exports),可为没有默认导出的创建一个中间模块

jsx
export { MyComponent as default } from './ManyComponents.js';

Suspense

如果在 MyComponent 渲染完成后包含 OtherComponent 的模块还没有被加载完成,可使用 Suspense 组件做降级处理。fallback 属性接受任何在组件加载过程中你想展示的 React 元素

jsx
const OtherComponent = React.lazy(() => import('./OtherComponent'));
function MyComponent() {
  return (
    <div>
      <Suspense fallback={<div>Loading...</div>}>
        <OtherComponent />
      </Suspense>
    </div>
  );
}

避免兜底

当 react 视图从一个状态切换到另一个状态时,如果下一个状态没有准备好,则会使用 Suspense 中的兜底方案。但这可能让用户感到困惑,对于这类不紧急的更新我们可以使用 transitions 等它准备好后在切换。

diff
import React, { Suspense } from 'react';
import Tabs from './Tabs';
import Glimmer from './Glimmer';

const Comments = React.lazy(() => import('./Comments'));
const Photos = React.lazy(() => import('./Photos'));

function MyComponent() {
  const [tab, setTab] = React.useState('photos');

  function handleTabSelect(tab) {
+    startTransition(() => {
      setTab(tab);
+    });
  };

  return (
    <div>
      <Tabs onTabSelect={handleTabSelect} />
      <Suspense fallback={<Glimmer />}>
        {tab === 'photos' ? <Photos /> : <Comments />}
      </Suspense>
    </div>
  );
}

应用

基于路由的代码分割

jsx
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import React, { Suspense, lazy } from 'react';

const Home = lazy(() => import('./routes/Home'));
const About = lazy(() => import('./routes/About'));

const App = () => (
  <Router>
    <Suspense fallback={<div>Loading...</div>}>
      <Switch>
        <Route exact path="/" component={Home} />
        <Route path="/about" component={About} />
      </Switch>
    </Suspense>
  </Router>
);