基于Webpack 2的React组件懒加载
Chunks是Webpack的基本概念之一,最直观的概念是在多入口配置中,诶个单独的入口会生成单独的Chunk。而在添加额外的插件配置之后,Webpack会输出譬如独立的CSS包体这样独立的块。Webpack内置有如三种类型的Chunk:
bundle-loaderbundle-loader是Webpack官方出品的Loader之一,bundle-loader可以用来加载异步代码块,基本的用法如下: // 当请求某个Bundle时,Webpack会为我们自动加载 var waitForChunk = require("bundle-loader!./file.js"); //我们需要等待Chunk加载完成才能获取到文件详情 waitForChunk(function(file) { // use file like is was required with // var file = require("./file.js"); }); // wraps the require in a require.ensure block 我们同样可以自定义Chunk名: require("bundle-loader?lazy&name=my-chunk!./file.js"); 我们可以很方便地利用bundle-loader实现React Router中模块的懒加载,譬如如果我们的路由设置如下: import HomePage from "./pages/HomePage"; import AdminPage from "./pages/admin/AdminPage"; import AdminPageSettings from "./pages/admin/AdminPageSettings"; export default function routes(fromServer) { return ( <Router history={browserHistory}> <Route path="/" component={HomePage}/> <Route path="/admin" component={AdminPage}/> <Route path="/admin/settings" component={AdminSettingsPage}/> <Router/> ) } 其中AdminPage可能非常笨重,我们希望只有当用户真实请求到 { ... module: { loaders: [{ // use `test` to split a single file // or `include` to split a whole folder test: /.*/,include: [path.resolve(__dirname,'pages/admin')],loader: 'bundle?lazy&name=admin' }] } ... } 该配置会自动帮我们从主文件中移除admin相关的组件代码,然后将其移动到 import HomePage from "./pages/HomePage"; import AdminPage from "./pages/admin/AdminPage"; import AdminPageSettings from "./pages/admin/AdminPageSettings"; const isReactComponent = (obj) => Boolean(obj && obj.prototype && Boolean(obj.prototype.isReactComponent)); const component = (component) => { return isReactComponent(component) ? {component} : {getComponent: (loc,cb)=> component( comp=> cb(null,comp.default || comp))} }; export default function routes(fromServer) { return ( <Router history={browserHistory}> <Route path="/" {...component(HomePage)}/> <Route path="/admin" {...component(AdminPage)}/> <Route path="/admin/settings" {...component(AdminSettingsPage)}/> <Router/> ) } React 懒加载组件封装
有时候我们需要将某个厚重的组件设置为异步加载,这里我们将常见的懒加载操作封装为某个组件及其高阶组件接口,源代码参考LazilyLoad: import React from 'react'; /** * @function 支持异步加载的封装组件 */ class LazilyLoad extends React.Component { constructor() { super(...arguments); this.state = { isLoaded: false,}; } componentWillMount() { this.load(this.props); } componentDidMount() { this._isMounted = true; } componentWillReceiveProps(next) { if (next.modules === this.props.modules) return null; this.load(next); } componentWillUnmount() { this._isMounted = false; } load(props) { this.setState({ isLoaded: false,}); const {modules} = props; const keys = Object.keys(modules); Promise.all(keys.map((key) => modules[key]())) .then((values) => (keys.reduce((agg,key,index) => { agg[key] = values[index]; return agg; },{}))) .then((result) => { if (!this._isMounted) return null; this.setState({modules: result,isLoaded: true}); }); } render() { if (!this.state.isLoaded) return null; return React.Children.only(this.props.children(this.state.modules)); } } LazilyLoad.propTypes = { children: React.PropTypes.func.isRequired,}; export const LazilyLoadFactory = (Component,modules) => { return (props) => ( <LazilyLoad modules={modules}> {(mods) => <Component {...mods} {...props} />} </LazilyLoad> ); }; export const importLazy = (promise) => ( promise.then((result) => result.default) ); export default LazilyLoad; 回调方式懒加载这里我们使用类似于bundle-loader中的回调方式进行懒加载,不过将其封装为了组件形式。其中的 render(){ return ... <LazilyLoad modules={{ LoadedLate: () => importLazy(System.import('../lazy/loaded_late.js')) }}> { ({LoadedLate}) => { return <LoadedLate /> } } </LazilyLoad> ... } 高阶组件方式懒加载在入门介绍中我们讲过可以利用external属性来配置引入jQuery,而这里我们也可以使用高阶组件方式进行异步加载: // @flow import React,{ Component,PropTypes } from 'react'; import { LazilyLoadFactory } from '../../../common/utils/load/lazily_load'; /** * 组件LoadedJquery */ export default class LoadedJQuery extends Component { /** * @function 默认渲染函数 */ render() { return ( <div ref={(ref) => this.props.$(ref).css('background-color','red')}> jQuery加载完毕 </div> ); } } export default LazilyLoadFactory( LoadedJQuery,{ $: () => System.import('jquery'),} ); 这里我们将加载完毕的jQuery作为组件的Props参数传入到组件中使用,同样我们也可以使用这种方式加载我们自定义的函数或者组件。上述两种的效果如下所示: (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |