【翻譯】基於 Create React App路由4.0的異步組件加載(Code Splitting)

基於 Create React App路由4.0的異步組件加載

本文章是一個額外的篇章,它能夠在你的React app中,幫助加快初始的加載組件時間。固然這個操做不是徹底必要的,但若是你好奇的話,請隨意跟隨這篇文章一塊兒用Create React Appreact路由4.0的異步加載方式來幫助react.js構建大型應用。html

代碼分割(Code Splitting)

當咱們用react.js寫咱們的單頁應用程序時候,這個應用會變得愈來愈大,一個應用(或者路由頁面)可能會引入大量的組件,但是有些組件是第一次加載的時候是沒必要要的,這些沒必要要的組件會浪費不少的加載時間。react

你可能會注意到 Create React App 在打包完畢以後會生成一個很大的.js文件,這包含了咱們應用程序須要的全部JavaScript。可是,若是用戶只是加載登陸頁面去登陸網站,咱們加載應用程序的其他部分是沒有意義的。在咱們的應用程序還很小的時候,這並非一個問題,可是它倒是咱們程序猿優化的一個東西。爲了解決這個問題,Create React App有一個很是簡單的代碼分割的的方案。git

代碼分割和 react-router

在咱們 react app 中,常見的路由配置多是像下面同樣的github

/* Import the components */
import Home from './containers/Home';
import Posts from './containers/Posts';
import NotFound from './containers/NotFound';


/* Use components to define routes */
export default () => (
  <Switch>
    <Route path="/" exact component={Home} />
    <Route path="/posts/:id" exact component={Posts} />
    <Route component={NotFound} />
  </Switch>
);

咱們一開始引入這些組件,而後定義好的路徑,會根據咱們的路由去匹配這些組件。npm

可是,咱們靜態地在頂部導入路由中的全部組件。這意味着,無論哪一個路由匹配,全部這些組件都被加載。咱們只想加載對匹配路由的時候才加載響應的組件。下面咱們一步步來完成這個使命。react-router

建立一個異步組件

建立一個js 文件,如:src/components/AsyncComponent.js,代碼以下app

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;
}

咱們在這裏作了一些事情:less

  1. 這個asyncComponent 函數接受一個importComponent 的參數,importComponent 調用時候將動態引入給定的組件。dom

  2. componentDidMount 咱們只是簡單地調用importComponent 函數,並將動態加載的組件保存在狀態中。異步

  3. 最後,若是完成渲染,咱們有條件地提供組件。在這裏咱們若是不寫null的話,也可提供一個菊花圖,表明着組件正在渲染。

使用異步組件

如今讓咱們使用咱們的異步組件,而不是像開始的靜態去引入。

import Home from './containers/Home';

咱們要用asyncComponent組件來動態引入咱們須要的組件。

tip: 別忘記 先 import asyncComponent from './AsyncComponent

const AsyncHome = asyncComponent(() => import('./containers/Home'));

咱們將要使用 AsyncHome 這個組件在咱們的路由裏面

<Route path="/" exact component={AsyncHome} />

如今讓咱們回到Notes項目並應用這些更改。

src/Routes.js

import React from 'react';
import { Route, Switch } from 'react-router-dom';
import asyncComponent from './components/AsyncComponent';
import AppliedRoute from './components/AppliedRoute';
import AuthenticatedRoute from './components/AuthenticatedRoute';
import UnauthenticatedRoute from './components/UnauthenticatedRoute';

const AsyncHome     = asyncComponent(() => import('./containers/Home'));
const AsyncLogin    = asyncComponent(() => import('./containers/Login'));
const AsyncNotes    = asyncComponent(() => import('./containers/Notes'));
const AsyncSignup   = asyncComponent(() => import('./containers/Signup'));
const AsyncNewNote  = asyncComponent(() => import('./containers/NewNote'));
const AsyncNotFound = asyncComponent(() => import('./containers/NotFound'));

export default ({ childProps }) => (
  <Switch>
    <AppliedRoute path="/" exact component={AsyncHome} props={childProps} />
    <UnauthenticatedRoute path="/login" exact component={AsyncLogin} props={childProps} />
    <UnauthenticatedRoute path="/signup" exact component={AsyncSignup} props={childProps} />
    <AuthenticatedRoute path="/notes/new" exact component={AsyncNewNote} props={childProps} />
    <AuthenticatedRoute path="/notes/:id" exact component={AsyncNotes} props={childProps} />
    { /* Finally, catch all unmatched routes */ }
    <Route component={AsyncNotFound} />
  </Switch>
);

只需幾回更改就至關酷了。咱們的app都是設置了代碼分割而的。也沒有增長太多的複雜性。
這裏咱們看看以前的這個src/Routes.js路由文件

import React from 'react';
import { Route, Switch } from 'react-router-dom';
import AppliedRoute from './components/AppliedRoute';
import AuthenticatedRoute from './components/AuthenticatedRoute';
import UnauthenticatedRoute from './components/UnauthenticatedRoute';

import Home from './containers/Home';
import Login from './containers/Login';
import Notes from './containers/Notes';
import Signup from './containers/Signup';
import NewNote from './containers/NewNote';
import NotFound from './containers/NotFound';

export default ({ childProps }) => (
  <Switch>
    <AppliedRoute path="/" exact component={Home} props={childProps} />
    <UnauthenticatedRoute path="/login" exact component={Login} props={childProps} />
    <UnauthenticatedRoute path="/signup" exact component={Signup} props={childProps} />
    <AuthenticatedRoute path="/notes/new" exact component={NewNote} props={childProps} />
    <AuthenticatedRoute path="/notes/:id" exact component={Notes} props={childProps} />
    { /* Finally, catch all unmatched routes */ }
    <Route component={NotFound} />
  </Switch>
);

注意,不要在頂部的引入全部的組件。咱們正在建立這些代碼分割的功能,以便在必要時爲咱們進行動態導入。

如今你運行npm run build 您將看到代碼已經被分割成一個個小文件。

圖片描述

下面是部署好的在網站的真實截圖

圖片描述

每一個.chunk.js都是須要的時候才加載的。固然咱們的程序是至關小的,而且分離在各個部分的小組件,是不須要這樣子按需加載的。仍是看你項目的需求。

原文地址:http://serverless-stack.com/c...

相關文章
相關標籤/搜索