React - router 4 필요 에 따라 불 러 오 는 실현 방식 및 원리 (Code Splitting)

React-router 4
router 4 이후 필요 에 따라 Component 를 불 러 오 는 방법 을 소개 합 니 다. router 4 이전에 저 희 는 getComponent 방식 으로 필요 에 따라 불 러 오 는 것 을 실 현 했 습 니 다. router 4 에서 getComponent 방법 은 제거 되 었 습 니 다. 다음은 react - router 4 가 들 어가 고 필요 에 따라 불 러 오 는 것 을 소개 합 니 다.
1. router 3 의 필요 에 따라 불 러 오 는 방식
route 3 에서 필요 에 따라 불 러 오 는 것 을 실현 하려 면 아래 코드 의 방식 으로 만 이 루어 지면 됩 니 다.
const about = (location, cb) => {
    require.ensure([], require => {
        cb(null, require('../Component/about').default)
    },'about')
}

//  route

2. router 4 필요 에 따라 불 러 오 는 방식 (three steps)
one step:
Bundle. js 파일 을 만 듭 니 다. 이 파일 은 사실 bundle - loader 로 포 장 된 구성 요 소 를 통 해 사용 합 니 다. 다음은 이 파일 을 구체 적 으로 설명 하 겠 습 니 다.
import React from 'react';
import PropTypes from 'prop-types';

class Bundle extends React.Component {
  state = {
    // short for "module" but that's a keyword in js, so "mod"
    mod: null
  }

  componentWillMount() {
    //       
    this.load(this.props);
  }

  componentWillReceiveProps(nextProps) {
    if (nextProps.load !== this.props.load) {
      this.load(nextProps);
    }
  }

  load(props) {
    //     
    this.setState({
      mod: null
    });
    //        
    props.load((mod) => {
      this.setState({
        // handle both es imports and cjs
        mod: mod.default ? mod.default : mod
      });
    });
  }

  render() {
    // if state mode not undefined,The container will render children
    return this.state.mod ? this.props.children(this.state.mod) : null;
  }
}

Bundle.propTypes = {
  load: PropTypes.func,
  children: PropTypes.func
};

export default Bundle;

second step:
import aContainer from 'bundle-loader?lazy!./containers/A'

const A = (props) => (
  
      //     this.props.child     ,   Bundle render    
    {(Container) => }
  
)

third step:
 render() {
    return (
      

Welcome!

) }

3. router 4 필요 에 따라 로드 방식 으로 분석
(1). 우선 필요 에 따라 불 러 옵 니 다. 통속 적 인 것 은 제 현재 location 이 Home 에 있 습 니 다. 그러면 저 는 Home 의 물건 만 불 러 와 야 합 니 다. About 등 다른 것 을 불 러 오지 말 아야 합 니 다.
(2). Bundle. js 이 파일 의 역할
먼저 이 코드 를 보십시오.
module.exports = function (cb) {
    __webpack_require__.e/* require.ensure */(2).then((function (require) {
        cb(__webpack_require__(305));
    }).bind(null, __webpack_require__)).catch(__webpack_require__.oe);
};

이것 은 우리 가 import loadDashboard from 'bundle-loader?lazy!./containers/A' 이런 방식 으로 도입 한 container 컨트롤 입 니 다.우 리 는 bundle - loader 를 사용 하여 A 의 소스 코드 를 위의 코드 로 바 꾸 었 습 니 다. 구체 적 으로 실현 하면 bundle - loader 소스 코드 를 볼 수 있 고 코드 가 매우 적 습 니 다.
위 에서 말 한 Bundle. js 는 사실 이 파일 을 처리 하 는 데 사 용 됩 니 다. 이 파일 은 callback 의 인자 가 필요 합 니 다. Bundle 의 load 방법 에서 이 callback 을 설정 합 니 다. 경로 가 A Container 로 바 뀌 려 면 A Container 를 불 러 오고 이 callback 을 호출 합 니 다. 이 callback 은 setState 방법 을 호출 합 니 다.우리 가 이전에 들 어 온 load 를 mod 에 설정 하고 렌 더 링 합 니 다.
4. webpack 에서 bundle - loader 를 통일 적 으로 설정 합 니 다.
src / routers / 아래 containers 폴 더 아래 의 모든 js 파일 과 일치 합 니 다. 2 급 디 렉 터 리 를 포함 합 니 다.
  {
      //   routers      
      // ([^/]+)\/?([^/]*)   xxx/xxx    xxx
      test: /containers\/([^/]+)\/?([^/]*)\.jsx?$/,
      include: path.resolve(__dirname, 'src/routers/'),
      // loader: 'bundle-loader?lazy'
      loaders: ['bundle-loader?lazy', 'babel-loader']
    }

5. 부분 소스 코드
1. bundle - loader 의 소스 코드
/*
    MIT License http://www.opensource.org/licenses/mit-license.php
    Author Tobias Koppers @sokra
*/
var loaderUtils = require("loader-utils");

module.exports = function() {};
module.exports.pitch = function(remainingRequest) {
    this.cacheable && this.cacheable();
    var query = loaderUtils.getOptions(this) || {};
    if(query.name) {
        var options = {
            context: query.context || this.options.context,
            regExp: query.regExp
        };
        var chunkName = loaderUtils.interpolateName(this, query.name, options);
        var chunkNameParam = ", " + JSON.stringify(chunkName);
    } else {
        var chunkNameParam = '';
    }
    var result;
    if(query.lazy) {
        result = [
            "module.exports = function(cb) {
", " require.ensure([], function(require) {
", " cb(require(", loaderUtils.stringifyRequest(this, "!!" + remainingRequest), "));
", " }" + chunkNameParam + ");
", "}"]; } else { result = [ "var cbs = [],
", " data;
", "module.exports = function(cb) {
", " if(cbs) cbs.push(cb);
", " else cb(data);
", "}
", "require.ensure([], function(require) {
", " data = require(", loaderUtils.stringifyRequest(this, "!!" + remainingRequest), ");
", " var callbacks = cbs;
", " cbs = null;
", " for(var i = 0, l = callbacks.length; i < l; i++) {
", " callbacks[i](data);
", " }
", "}" + chunkNameParam + ");"]; } return result.join(""); } /* Output format: var cbs = [], data; module.exports = function(cb) { if(cbs) cbs.push(cb); else cb(data); } require.ensure([], function(require) { data = require("xxx"); var callbacks = cbs; cbs = null; for(var i = 0, l = callbacks.length; i < l; i++) { callbacks[i](data); } }); */

2. A 의 소스 코드
import React from 'react';
import PropTypes from 'prop-types';
import * as reactRedux from 'react-redux';
import BaseContainer from '../../../containers/ReactBaseContainer';

class A extends BaseContainer {
  constructor(props) {
    super(props);
    this.renderCustom = function renderCustom() {
      return (
        
Hello world In A
); }; } render() { // view return super.render(); } } A.propTypes = { dispatch: PropTypes.func, }; function mapStateToProps(state) { return { state }; } export default reactRedux.connect(mapStateToProps)(A);

3. route. js 의 원본 코드
import React from 'react';
import { BrowserRouter, Switch, Link } from 'react-router-dom';
import { Route } from 'react-router';
import PostContainer from '../containers/PostsContainer';
//   trunk       the basename of the resource
import aContainer from './containers/A';
import bContainer from './containers/B';
import cContainer from './containers/C';
import Bundle from '../utils/Bundle';

const A = () => (
  
    {Component => }
  
)

const app = () =>
  
{/* path = "/about" */} {/* "/about/" , "/about/1" exact , , , */} {/* path = "/about/" */} {/* "/about/1" , "/about" strict,path , */} {/* exact strick , */} Link to about {/* */}
; export default function () { // const supportsHistory = 'pushState' in window.history; return (
{app()}
); }

업데이트 (필요 에 따라 불 러 오기)
oneStep
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 ?  : null;
    }
  }

  return AsyncComponent;
}

Second Step
const Buttons = asyncComponent(() => import("./button"));

babel 에 설정 이 필요 합 니 다.
"presets": [
        [
          "es2015"
        ],
        "stage-1", //    es7   ,         
        "react"
      ],

문장 인용
  • http://henleyedition.com
  • react - router 공식 문서
  • 좋은 웹페이지 즐겨찾기