在angular
中, 异步加载组件时, 需要加载完mod.js
之后使用$provide
来将mod
注册到angular
全局, 才能实现异步组件中指令的加载和识别. 而在react
中, 组件原本就是js
函数, 理论上比angular
中异步加载组件简单得多. 然而复杂的地方在于与webpack
的结合.
首先, 在ES6
中, import
是导入export
模块的语法, import()
可以用作动态导入模块, 但是webpack
在使用import()
时, 底层调用的是require
, 所以需要在模块底下加上require
的导出语法.
1 2 3 4 5 6 7
| const Demo = () => ( <div> <span>Demo!</span> </div> ); module.exports = Demo; export default Demo;
|
然后是, webpack
对动态模块的支持性. 当直接在import()
中给定url
时, webpack
会在编译时分析所加载文件, 并将其打包为单独的文件. 如果url
为动态内容或者是从后台获取到的内容, 那么就会存在问题.
查webpack
官方文档时, 可以看到它是支持动态模块的, 但是语法和例子都没写清楚. 不过后来在网上查资料时, 看到了Sean Larkin
(webpack Maintainer)在知乎上的一个回答, 所以解决了这个问题.
1
| const getTemplate = (templateName, templatePath) => import(`../../../../project-template/pc/${templatePath)/js/common/${templateName}.html`)
|
简单理解就是, 当在webpack
中使用动态导入时, 需要给定partial path
, 这样webpack
才能找到你所需的模块.
以上两个问题解决以后, 实现一个异步加载的组件就比较简单了.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| import React from 'react'; import { PropTypes as P } from 'prop-types';
import Loading from './../loading';
class AsyncComponent extends React.PureComponent { static propTypes = { src: P.string.isRequired, loadingStart: P.func, loadingEnd: P.func, }; static defaultProps = { loadingStart: () => {}, loadingEnd: () => {}, }; constructor(props) { super(props); if (!props.src) { throw 'AsyncComponent need src'; } this.state = { component: null, }; } getComponentFromFileAsync(src) { this.props.loadingStart(); import(`./../../_container/${src}.js`).then((v) => { if (!this._isMounted) return; this.props.loadingEnd(); this.setState({ component: v, }); }); }
componentDidMount() { this._isMounted = true; this.getComponentFromFileAsync(this.props.src); } componentWillReceiveProps(nextProps, nextState) { if (nextProps.src != this.props.src) { this.getComponentFromFileAsync(nextProps.src); } } componentWillUnmount() { this._isMounted = false; } render() { let Com = this.state.component; if (!Com) { return <Loading />; } else { return <Com {...this.props} src={undefined} />; } } }
export default AsyncComponent;
|
推荐配合router
一起使用, 也可做动态配置的权限控制, 使用方法 :
1 2 3 4 5 6 7 8 9 10 11 12 13
| <Switch> {this.state.routeList.map((item, index) => { if (item.get('to')) { return <Redirect key={index} path={item.get('url')} exact={item.get('exact')} to={item.get('to')} />; } else if (item.get('src')) { return <Route key={index} path={item.get('url')} exact={item.get('exact')} render={() => <AsyncComponent src={item.get('src')} />} />; } else { return null; } })} <Route exact path='/' render={() => '欢迎来到首页'} /> <Redirect path='*' to='/' /> </Switch>
|