React-loadable源码分析简单来说,loadable是一个高阶函数,同样使用了react的渲染API、webpack知识点、babel、promise组合组件。首先,我们需要知道react-loadable是干什么用的。:loader需要懒加载的组件必须使用()=>import('xxx')语法来加载加载组件,propsaccepterror,pastDelay,timedOut,retry参数,可以自定义延迟,可以添加延迟超时timeouttimerendertype是:(loaded,props)=>ReactNode,可以添加额外的参数注入多个组件,同时加载其中接受的参数loader,render,type和上面的Loadable.Map没有太大区别({loader:{Bar:()=>import('./Bar'),i18n:()=>fetch('./i18n/bar.json').then(res=>res.json()),},render(loaded,props){letBar=loaded.Bar.default;leti18n=loaded.i18n;return;},})预加载常量LoadableBar=Loadable({loader:()=>import('./Bar'),loading:Loading,});触发器:LoadableBar.preload();该库还涉及到SSR相关的知识点,所以这里就不涉及源码了,因为我不讲SSR相关的,所以这里删掉相关代码:loadable.jsx的主体在这高层组件,它的主体是:createLoadableComponent首先我们看一下它在闭包中做了什么:functioncreateLoadableComponent(loadFn,options){//加载的判断,忽略//创建配置项,覆盖默认值//whererendersourcecode:functionrender(loaded,props){//returnReact.createElement(resolve(loaded),props);//}letopts=Object.assign({loader:null,loading:null,delay:200,timeout:null,render:render,webpack:null,modules:null},options);//结果,用于调用loaderletres=null;//在初始化期间调用,loadFn函数将在后面讨论functioninit(){if(!res){res=loadFn(opts.loader);}返回res.promise;}returnclassLoadableComponentextendsReact.Component{//暂时忽略这里}}returncomponent我们来看看返回的组件:classLoadableComponentextendsReact.Component{constructor(props){super(props);在里面();//开启构造函数中的初始化函数,他将res赋值给一个promise//定义状态this.state={error:res.error,pastDelay:false,timedOut:false,loading:res.loading,loaded:res.loaded};}//静态函数,我提到了staticpreload(){returninit();}componentWillMount(){//用来设置定时器和延时相关this._loadModule();}componentDidMount(){//flag是否挂载this._mounted=true;}componentWillUnmount(){//修改标志,清除定时器this._mounted=false;这个._clearTimeouts();}render(){//渲染函数,如果当前状态为loading或errorloading,则使用loading进行渲染,并传递各种参数if(this.state.loading||this.state.error){returnReact.createElement(opts.loading,{isLoading:this.state.loading,pastDelay:this.state.pastDelay,timedOut:this.state.timedOut,error:this.state.error,重试:this.retry});}elseif(this.state.loaded){//如果已经加载,调用render函数,使用React.createElement进行渲染returnopts.render(this.state.loaded,this.props);}else{返回空值;}}}load//这里的load是createLoadableComponent(loadFn,options)中的入参loadFnfunctionload(loader){//loader是options中的loader//例如:()=>import('./my-component')让promise=loader();//用于返回结果letstate={loading:true,loaded:null,error:null};//promise赋值,不调用state.promise=promise.then(loaded=>{state.loading=false;state.loaded=loaded;returnloaded;}).catch(err=>{state.loading=false;state.error=err;抛出错误;});返回状态;}loadMap调用:Loadable.Map=LoadableMap;functionLoadableMap(opts){returncreateLoadableComponent(loadMap,opts);}具体代码:functionloadMap(obj){letstate={loading:false,loaded:{},error:null};让承诺=[];try{Object.keys(obj).forEach(key=>{letresult=load(obj[key]);if(!result.loading){state.loaded[key]=result.loaded;state.error=result.error;}else{state.loading=true;}promises.push(result.promise);result.promise.then(res=>{state.loaded[key]=res;}).catch(err=>{state.error=err;});});}catch(err){state.error=err;}state.promise=Promise.all(promises).then(res=>{state.loading=false;ret瓮资源;}).catch(err=>{state.loading=false;throwerr;});returnstate;}一般情况下,和load类似,通过promise.allapi构造一个promise数组result总结从组件看结构:Loadable()===createLoadableComponent(load,opts)===classLoadableComponent来自调用角度:init调用load函数,用于在组件加载后包装参数init,直接返回组件对应的promiserender函数中的result根据渲染加载组件或render组件到相应的结果。渲染组件使用React.createElement组件渲染。总的来说,去掉了SSR的关联,还是比较简单的一个组件。主要使用的是()=>import()语法支持参考:https://github.com/jamiebuild...