react-router之代码分离

概念

无需用户下载整个应用之后才能访问访问它。即边访问边下载。因此我们设计一个组件<Bundle>当用户导航到它是来动态加载组件。

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

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

如果model是一个component:

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

这个组件拥有一个load属性(即webpack的 bundle loader)。当组件挂载或者得到一个新的load属性,它将调用load属性,然后放置组件的returned valuestate中,最后在组件的render中回掉该model。源码:

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。这样,我们就可以向用户展示一个等待的动画,表明我们正在等待什么东西。

Why bundle loader, and not import()?

TC39 最近提出的官方的动态导入是import(),我们可以调整我们的Bundle来使用它:

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

bundle loader的最大好处是它第二次同步回调。这样可以在用户每次访问一个代码分离的页面时防止加载页面而造成的页面闪烁。

忽视你import的方式,思想时一样的:code splitting 即,当组件呈现时用来处理该组件加载的组件。现在你要做的就是在你想要动态加载代码的地方使用<Bundle>

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的其余部分去处理它

ReactDOM.render(<App/>, preloadTheRestOfTheApp)
posted @ 2017-11-23 22:52  禅楼望月  阅读(670)  评论(0编辑  收藏  举报