Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

React异步加载组件指北 #76

Closed
yuxino opened this issue Jul 20, 2018 · 0 comments
Closed

React异步加载组件指北 #76

yuxino opened this issue Jul 20, 2018 · 0 comments
Labels

Comments

@yuxino
Copy link
Owner

yuxino commented Jul 20, 2018

在日常开发中我们都会碰见需要异步加载组件的情况,就比如说一个后台项目。拥有各种权限的分配,部分成员看得见一些表图页面,而一部分人看不见。我们知道表图库比如Echart之累的都满大的,如果我们直接加载进来全部打包到一个bundle的话,整个bundle的体积会比较大。并且除此之外很多页面组件用不上,也许用户一直都不会访问到,所以也没有理由加载,浪费带宽和资源。

这里说的异步加载都是在围绕着router来说,因为router一般都会做这个处理。react开发者的话会选择react-router作为处理控制路由的库。我们先来看看两种不同的场景。使用了异步加载和没有使用异步加载。以我的博客dura来举例子。

没有异步加载组件的情况

我们来看看没有异步载的情况。全部都打包在一个bundle里面的写法。

import React, { Component } from 'react'
import './css/App.css'
import { Route, Switch } from 'react-router'

import HomePage from 'page/HomePage'
import AboutPage from 'page/AboutPage'
import ArchivesPage from 'page/ArchivesPage'
import ClosedPage from 'page/ClosedPage'
import LabelPage from 'page/LablePage'
import LabelsPage from 'page/LablesPage'
import TimeLinePage from 'page/TimelinePage'
import NotFoundPage from 'page/NotFoundPage'

class App extends Component {
  render () {
    return (
      <Switch>
        <Route exact path="/" component={HomePage}  />
        <Route exact path="/about" component={AboutPage}  />
        <Route exact path="/archives" component={ArchivesPage}  />
        <Route exact path="/closed" component={ClosedPage}  />
        <Route exact path="/labels" component={LabelsPage}  />
        <Route exact path="/label/:number" component={LabelPage}  />
        <Route exact path="/timeline" component={TimeLinePage} />
        <Route component={NotFoundPage} />
      </Switch>
    )
  }
}

export default App;

NetWorkd加载的情况

全部打包的情况

我们发现所有东西都打包在了一起,而不是针对页面进行打包,这样会加载无用资源。此时的bundle会是700kb,对我这个项目来说。

使用异步加载

我们来看看异步加载的情况。

我们可以利用webpack 2.0+的特性import(...)语法来做异步加载,这样webpack会自动进行代码的chunk。只有在需要用到的时候才会引用。利用这一特性我们创建一个AsyncComponet的HOC组件帮助我们进行异步加载。

AsyncComponet.js

import React, { Component } from 'react';

export default function asyncComponent(importComponent) {
  class AsyncComponent extends Component {
    constructor(props) {
      super(props);
      this.state = {
        component: null,
      };
    }
    async componentDidMount() {
      const { default: component } = await importComponent();
      this.setState({
        component: component
      });
    }
    render() {
      const C = this.state.component;
      return C
        ? <C {...this.props} />
        : null;
    }
  }
  return AsyncComponent;
}

App.js

import React, { Component } from 'react'
import './css/App.css'
import { Route, Switch } from 'react-router'

// using webpack import syntax up performance
import AsyncComponent from 'hoc/AsyncComponent'
const HomePage = AsyncComponent(() => import('page/HomePage'))
const AboutPage = AsyncComponent(() => import('page/AboutPage'))
const ArchivesPage = AsyncComponent(() => import('page/ArchivesPage'))
const ClosedPage = AsyncComponent(() => import('page/ClosedPage'))
const LabelPage = AsyncComponent(() => import('page/LablePage'))
const LabelsPage = AsyncComponent(() => import('page/LablesPage'))
const TimeLinePage = AsyncComponent(() => import('page/TimelinePage'))
const NotFoundPage = AsyncComponent(() => import('page/NotFoundPage'))

class App extends Component {
  render () {
    return (
      <Switch>
        <Route exact path="/" component={HomePage}  />
        <Route exact path="/about" component={AboutPage}  />
        <Route exact path="/archives" component={ArchivesPage}  />
        <Route exact path="/closed" component={ClosedPage}  />
        <Route exact path="/labels" component={LabelsPage}  />
        <Route exact path="/label/:number" component={LabelPage}  />
        <Route exact path="/timeline" component={TimeLinePage} />
        <Route component={NotFoundPage} />
      </Switch>
    )
  }
}

export default App;

NetWorkd加载的情况

chunk

我们现在再来看bundle的大小,我们会发现bundle缩小到了400kb左右,虽然这个小项目不是太明显也就是缩少了大概百分之40这样子。但是对于大型项目来说,这个倍率会网上递增。

除此之外在我们访问不同的页面的时候,才会对应的chunk

总结

AsyncCompoent利用了webpack懒加载/code spliting特性达到了异步加载的目的。但是AsyncComponet并不完整,存在着很多的问题,比如说加载失败的问题,这里就没有处理,延迟加载,服务端处理,细节上的也没有,比如加载组件过程中的占位(placeholder)组件。

一个更好的解决方案会是使用react-loadable组件做这个事情。不过这篇不做介绍,放下一次吧(可能)。

@yuxino yuxino added the React label Jul 20, 2018
@yuxino yuxino closed this as completed Oct 9, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant