webpack4+react16+react-router-dom4從零配置到優化,實現路由按需載入(下)

高山低谷發表於2019-10-29

上一篇介紹了下webpack的一些配置,接下來講下reactRouter4裡面關於路由的一些配置,如何做到模組的按需載入,這也是常用的一種優化網站效能的方式。

前言

react-router 還是 react-router-dom?

首先在建立React專案的時候,我們一般要引入兩個包,react 和 react-dom, 那麼 react-router 和react-router-dom 是不是兩個都要引用呢?其實不然,兩者只需取一,不同之處就是後者比前者多出了 Link,BrowserRouter,HashRouter這樣的 DOM 類元件。因此我們只需引用 react-router-dom 這個包就行了。當然,如果搭配 redux ,你還需要使用 react-router-redux。 即使是在React Native中, 你也只需要引用react-router-native ,因為react-router-dom和react-router-native都是基於react-router的實現。

實現步驟

一、安裝

 yarn  add react react-dom react-router-dom
複製程式碼

這裡特別說明下:react版本問題,如果你安裝的React是16.9以上版本,那麼在你開啟控制檯的時候會出現以下警告:

webpack4+react16+react-router-dom4從零配置到優化,實現路由按需載入(下)
一年前,React 宣佈 unsafe 生命週期方法重新命名為:

  • componentWillMount → UNSAFE_componentWillMount

  • componentWillReceiveProps → UNSAFE_componentWillReceiveProps

  • componentWillUpdate → UNSAFE_componentWillUpdate

React v16.9 不包含破壞性更改,而且舊的生命週期方法在此版本依然沿用,僅此說明下

二、檔案建立和babel

webpack4+react16+react-router-dom4從零配置到優化,實現路由按需載入(下)

在這特別說明下.babelrc檔案的作用: babel6.X版本之後,所有的外掛都是可插拔的,也就是說只安裝babel依然無法正常的工作,我們需要配置對應的.babelrc檔案才能起作用。

.babelrc檔案需要的配置項主要有預設(presets)和外掛(plugins)。

1、預設(presets)的作用是為babel安裝指定的外掛,外掛命名採用babel-preset-xxx的形式;

2、presets是外掛plugins的預設,也就是說直接需要不需要的外掛一起引入,如果不想使用presets,可以單獨使用plugins對某個功能進行單獨的引入,有一些方法是presets中不提供的,如果要使用就需要單獨引用了。

webpack4+react16+react-router-dom4從零配置到優化,實現路由按需載入(下)

本人這裡用的babel7,關於babel6和babel7的一些不同點,可以參看下這個升級到Babel 7,裡面講的比較細緻。

三、router按需載入的實現

在router4之前,我們是使用getComponent的的方式來實現按需載入的,router4中,getComponent方法已經被移除,下面著重介紹一下react-router4是如何來實現按需載入的。

1、router3 的按需載入方式

route3中實現按需載入只需要按照下面程式碼的方式實現就可以了。

const Home = (location, callback) => {
  require.ensure([], require => {
    callback(null, require('../Component/Home').default)
  },'Home')
}
//配置route
<Route path="home" getComponent={Home} />
複製程式碼

2、router4:用create-react-app文件給的react-router按需載入實現

第一步:建立一個非同步元件 src/components/AsyncComponent.js

import React from 'react';
export default function (componentFactory) {
  class AsyncComponent extends React.Component {
    constructor() {
      super();
      this.state = {component: null};
    }
    async componentDidMount() {
      let {default: component} = await componentFactory();
      this.setState({component});
    }
    render() {
      let Comp = this.state.component;
      return Comp ? <Comp {...this.props}/> : null;
    }
  }
  return AsyncComponent;
}
複製程式碼

第二步:將上面的元件匯入router.js, 我這裡是src/router/index.js

import React from "react";
import { Route, Switch } from "react-router-dom";
import asyncComponent from "../components/AsyncComponent";

const AsyncHome = asyncComponent(() => import("../pages/Home"));
const AsyncCount = asyncComponent(() => import("../pages/Count"));
const AsyncNotFound = asyncComponent(() => import("../pages/NotFound"));

export default ({ childProps }) =>
  <Switch>
    <Route
      path="/"
      exact
      component={AsyncHome}
      props={childProps}
    />
    <Route
      path="/count"
      exact
      component={AsyncCount}
      props={childProps}
    />
    {/* Finally, catch all unmatched routes */}
    <Route component={AsyncNotFound} />
  </Switch>;
複製程式碼

第三部:封裝app根元件, 在scr/App.js下引入router.js

import React, { Component } from "react";
import { Link, withRouter } from "react-router-dom";
import Routes from "./router";
import './assets/reset.css';
class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      isAuthenticated: false,
      isAuthenticating: true
    };
  }
  render() {
    const childProps = {
      isAuthenticated: this.state.isAuthenticated,
      userHasAuthenticated: this.userHasAuthenticated
    };
    return (
        <Routes childProps={childProps} />
    );
  }
}
export default withRouter(App);

複製程式碼

第四部:將App元件放至入口檔案index.js

import React from 'react';
import ReactDOM from 'react-dom';
import {BrowserRouter} from 'react-router-dom'
import App from './App';
// import registerServiceWorker from './components/registerServiceWorker';

ReactDOM.render(
  <BrowserRouter><App/></BrowserRouter>, 
  document.getElementById('app')
);
// registerServiceWorker();
複製程式碼

以上就是router4的按需載入 在這裡補充另外一種實現按需載入的方式:

3、router4: 利用react-loadable這個高階元件實現按需載入

yarn add react-loadable
複製程式碼
import React from 'react';
import { Router, Route, Switch } from 'react-router-dom';
import Loadable from 'react-loadable';

const MyLoadingComponent = ({ isLoading, error }) => {
  if (isLoading) {
    return null;
  }
  if (error) {
    return <div>Sorry, there was a problem loading the page.</div>;
  }
  return null;
};

const HomeItem = Loadable({
  loader: () => import('./pages/Home'),
  loading: MyLoadingComponent
});

const CountItem = Loadable({
  loader: () => import('./pages/Count'),
  loading: MyLoadingComponent
});


const Routes = ({ history }) => (
  <Router history={history}>
    <Layout>
      <Switch>
        <Route exact path="/" component={HomeItem} />
        <Route exact path="/count" component={CountItem} />
      </Switch>
    </Layout>
  </Router>
);
MyLoadingComponent.propTypes = {
  isLoading: PropTypes.bool,
  error: PropTypes.bool
};

MyLoadingComponent.defaultProps = {
  isLoading: true,
  error: false
};

Routes.propTypes = {
  history: PropTypes.object
};

Routes.defaultProps = {
  history: {}
};

export default Routes;
複製程式碼

以上是本人關於webpack4+react16+react-router-dom4從零配置到優化,實現路由按需載入的所有內容了,如果有疑問,或者不對的地方,歡迎大家在下方留言,一起探討和更正。

webpack4+react16+react-router-dom4從零配置到優化,實現路由按需載入(上)

相關文章