使用ReactLoadable在React中进行代码拆分
代码拆分是一种在现代 Web 应用程序开发中更多使用的技术,它允许仅在需要时加载代码块。 例如,使用基于路由的代码拆分,用户可以导航到应用程序的不同路由,并且在幕后,每个路由的代码仅在第一次访问时加载。 使用代码拆分,在应用程序初始化时只能加载最少量的代码,并按需加载额外的代码。 通过允许减小初始捆绑包大小,这可以极大地提高性能。
React Loadable 是 @jamiebuilds 的一个库,它可以很容易地在 React 中实现代码拆分,并且包含 React 的组件模型。 它使用 动态导入 实现它的魔力,并且 webpack 在捆绑时自动将动态导入拆分为单独的块。
让我们快速回顾一下如何使用 React Loadable。
安装
只需使用 npm 或 Yarn 将 react-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 高阶组件采用具有两个键的对象:loader
和 loading
:
- 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 和有关高级主题(如服务器端渲染)的文档。