react-router之代碼分離

概念

無需用戶下載整個應用以後才能訪問訪問它。即邊訪問邊下載。所以咱們設計一個組件<Bundle>當用戶導航到它是來動態加載組件。javascript

import loadSomething from 'bundle-loader?lazy!./Something'

<Bundle load={loadSomething}>
  {(mod) => (
    // do something w/ the module
  )}
</Bundle> 

若是model是一個component:html

<Bundle load={loadSomething}>
  {(Comp) => (Comp
    ? <Comp/>
    : <Loading/>
  )}
</Bundle>

這個組件擁有一個load屬性(即webpack的 bundle loader)。當組件掛載或者獲得一個新的load屬性,它將調用load屬性,而後放置組件的returned valuestate中,最後在組件的render中回掉該model。源碼:java

import React, { Component } from 'react'

class Bundle extends 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() {
    return this.state.mod ? this.props.children(this.state.mod) : null
  }
}

export default Bundle

上面render中代表,在model獲取以前,render將調用 null state.mod。這樣,咱們就能夠向用戶展現一個等待的動畫,代表咱們正在等待什麼東西。webpack

Why bundle loader, and not import()?

TC39 最近提出的官方的動態導入是import(),咱們能夠調整咱們的Bundle來使用它:web

<Bundle load={() => import('./something')}>
  {(mod) => ()}
</Bundle> 

bundle loader的最大好處是它第二次同步回調。這樣能夠在用戶每次訪問一個代碼分離的頁面時防止加載頁面而形成的頁面閃爍。typescript

忽視你import的方式,思想時同樣的:code splitting 即,當組件呈現時用來處理該組件加載的組件。如今你要作的就是在你想要動態加載代碼的地方使用<Bundle>app

Loading after rendering is complete

Bundle component一樣也有利於預在後臺預加載app的其他部分。動畫

import loadAbout from 'bundle-loader?lazy!./loadAbout'
import loadDashboard from 'bundle-loader?lazy!./loadDashboard'

// components load their module for initial visit
const About = (props) => (
  <Bundle load={loadAbout}>
    {(About) => <About {...props}/>}
  </Bundle>
)

const Dashboard = (props) => (
  <Bundle load={loadDashboard}>
    {(Dashboard) => <Dashboard {...props}/>}
  </Bundle>
)

class App extends React.Component {
  componentDidMount() {
    // preloads the rest
    loadAbout(() => {})
    loadDashboard(() => {})
  }

  render() {
    return (
      <div>
        <h1>Welcome!</h1>
        <Route path="/about" component={About}/>
        <Route path="/dashboard" component={Dashboard}/>
      </div>
    )
  }
}

何時,多少個你的app要被加載,由你決定。不須要綁定特殊的route。也許你僅僅在用戶不活躍的時候,也或許僅僅在用戶訪問一個route時,或許你想在初始render以後預加載app的其他部分去處理它ui

ReactDOM.render(<App/>, preloadTheRestOfTheApp)
相關文章
相關標籤/搜索