使用ReactLoadable在React中进行代码拆分

来自菜鸟教程
跳转至:导航、​搜索

代码拆分是一种在现代 Web 应用程序开发中更多使用的技术,它允许仅在需要时加载代码块。 例如,使用基于路由的代码拆分,用户可以导航到应用程序的不同路由,并且在幕后,每个路由的代码仅在第一次访问时加载。 使用代码拆分,在应用程序初始化时只能加载最少量的代码,并按需加载额外的代码。 通过允许减小初始捆绑包大小,这可以极大地提高性能。

React Loadable@jamiebuilds 的一个库,它可以很容易地在 React 中实现代码拆分,并且包含 React 的组件模型。 它使用 动态导入 实现它的魔力,并且 webpack 在捆绑时自动将动态导入拆分为单独的块。

让我们快速回顾一下如何使用 React Loadable。

安装

只需使用 npm 或 Yarnreact-loadable 包添加到您的项目中:

$ npm install react-loadable

# or
$ yarn add react-loadable

用法

让我们创建一个人为的例子来说明 Loadable 是多么简单。 首先,SomeComponent

组件/SomeComponent.js

import React from 'react';

function SomeComponent() {
  return <h1>Some Component! 💣🚀👨‍🎤🤘</h1>;
}

export default SomeComponent;

然后让我们在我们的 App 组件中使用它:

应用程序.js

import React, { Component, Fragment } from 'react';
import SomeComponent from './components/SomeComponent';

class App extends Component {
  state = {
    showComponent: false
  };

  handleClick = () => {
    this.setState({
      showComponent: true
    });
  };

  render() {
    if (this.state.showComponent) {
      return <SomeComponent />;
    } else {
      return (
        <Fragment>
          <h1>Hello!</h1>
          <button onClick={this.handleClick}>Click me!</button>
        </Fragment>
      );
    }
  }
}

export default App;

注意组件是如何仅在用户单击按钮后才呈现到视图中的。 显然,对于这样一个简单的组件,它并没有什么不同,但是对于一个应用程序中较大的组件,这是一个不平凡的,代码拆分该组件可能是一个好主意。

让我们使用 React Loadable 重构一下代码拆分:

应用程序.js

import React, { Component, Fragment } from 'react';
import Loadable from 'react-loadable';

function Loading() {
  return <h3>Loading...</h3>;
}

const SomeComponent = Loadable({
  loader: () => import('./components/SomeComponent'),
  loading: Loading
});

class App extends Component {
  state = {
    showComponent: false
  };

  handleClick = () => {
    this.setState({
      showComponent: true
    });
  };

  render() {
    if (this.state.showComponent) {
      return <SomeComponent />;
    } else {
      return (
        <Fragment>
          <h1>Hello!</h1>
          <button onClick={this.handleClick}>Click me!</button>
        </Fragment>
      );
    }
  }
}

export default App;

Loadable 高阶组件采用具有两个键的对象:loaderloading

  • loader:期望一个函数返回一个解析为 React 组件的 Promise。 使用 import() 的动态导入返回一个承诺,所以我们所要做的就是指向要加载的组件的位置。
  • loading:期望在加载代码时呈现组件。

就这么简单! 如果您查看浏览器的 Devtools 中的 Network 选项卡,您会看到单击按钮时正在加载的块。

加载延迟

如果组件被快速加载,则具有中间加载组件可能会成为 UI 中视觉烦恼的来源。 幸运的是,Loadable 以 pastDelay 道具的形式提供了一种简单的解决方法,该道具被传递给加载组件,并且一旦经过一定的延迟就会评估为真:

// ...

function Loading({ pastDelay }) {
  return pastDelay ? <h3>Loading...</h3> : null;
}

const SomeComponent = Loadable({
  loader: () => import('./components/SomeComponent'),
  loading: Loading
});

// ...

默认延迟为 200ms,但您可以通过将 delay 配置传递给可加载 HOC 来更改它。 例如,我们将最大延迟更改为 60 毫秒:

function Loading({ pastDelay }) {
  return pastDelay ? <h3>Loading...</h3> : null;
}

const SomeComponent = Loadable({
  loader: () => import('./components/SomeComponent'),
  loading: Loading,
  delay: 60
});

错误

另一个 prop 被传入加载组件,error,如果在尝试加载组件时发生错误,它可以很容易地渲染其他内容:

function Loading({ error }) {
  if (error) {
    return 'oh-noes!';
  } else {
    return <h3>Loading...</h3>;
  }
}

const SomeComponent = Loadable({
  loader: () => import('./components/SomeComponent'),
  loading: Loading
});

基于路由的代码拆分

通常,对应用程序进行代码拆分的最简单方法是在路由级别。 由于使用 React Router v4 时 React 中的路由只是组件,因此使用 React Loadable 按需加载不同路由的代码同样容易。

在这里,我们将介绍一个使用 React Loadable 进行基于路由的代码拆分的简单示例。 首先,确保我们的项目中还有 react-router-dom 可用:

$ npm install react-router-dom

# or
$ yarn add react-router-dom

在以下示例中,我们静态导入 Dashboard 组件,因为它会在根路由上立即需要,我们使用 Loadable 仅加载 Settings 和 AddUser[X199X ] 组件,当它们各自的路由被激活时:

import React, { Component } from 'react';
import Loadable from 'react-loadable';
import { Link, Route, BrowserRouter as Router } from 'react-router-dom';

import Dashboard from './components/Dashboard';

function Loading({ error }) {
  if (error) {
    return 'Oh nooess!';
  } else {
    return <h3>Loading...</h3>;
  }
}

const Settings = Loadable({
  loader: () => import('./components/Settings'),
  loading: Loading
});

const AddUser = Loadable({
  loader: () => import('./components/AddUser'),
  loading: Loading
});

class App extends Component {
  render() {
    return (
      <Router>
        <div>
          <Link to="/">Dashboard</Link>
          <Link to="/settings">Settings</Link>
          <Link to="/add-user">Add User</Link>

          <Route exact path="/" component={Dashboard} />
          <Route path="/settings" component={Settings} />
          <Route path="/add-user" component={AddUser} />
        </div>
      </Router>
    );
  }
}

export default App;

🏇 有了这个,你应该参加代码拆分的比赛! 查看 项目的自述文件 以深入了解 API 和有关高级主题(如服务器端渲染)的文档。