react-loadable

basic points
  1. 基于路由的代码分割和基于组件的代码分割
    webpack可以设置多入口文件,可以通过入口文件进行代码分割,即所谓的基于路由的分割;基于路由的分割可以常见于多tab页切换等场景;
    但是由于即使是多入口文件,某个文件中的代码也未必是需要首屏全部加载的,比如弹窗等;如果可以基于组件进行代码分割,可以更加细粒度地控制首屏需要加载的代码及其他代码的加载时机,可以有效提高页面性能和用户体验;
    在这里插入图片描述
  2. 考虑自己实现一个动态载入的组件,需要考虑哪些问题
    1. 需要基于ES6新特性import()实现,然后通过states和生命周期函数共同控制组件的可见性及展示内容,直接看官方demo:

      class MyComponent extends React.Component {
        state = {
          Bar: null
        };
      
        componentWillMount() {
          import('./components/Bar').then(Bar => {
            this.setState({ Bar: Bar.default });
          });
        }
      
        render() {
          let {Bar} = this.state;
          if (!Bar) {
            return <div>Loading...</div>;
          } else {
            return <Bar/>;
          };
        }
      }
      
    真实场景考虑的问题会更加复杂:比如动态加载失败import(),比如SSR怎么处理,比如加载完成前的站位组件不可能只是单纯的静态文本Loading...等;
React Loadable是一个轻量级的封装库,可以实现基于组件的代码分割功能。

看下React Loadable的使用、实现及对应问题的解决方式:

  1. 使用:

    import React from "react";
    import "./styles.css";
    import Loadable from "react-loadable";
    
    const LoadableSub = Loadable({
      loader: () => import("./Sub"),
      loading: () => {
        return <div>Loading...</div>;
      }
    });
    
    export default function App() {
      return (
        <div className="App">
          <h1>Hello CodeSandbox</h1>
          <h2>Start editing to see some magic happen!</h2>
          <LoadableSub />
        </div>
      );
    }
    
    	```
    
    
  2. Loadable实质是一个高阶组件,形式为

    Loadable({
    	loader: () => import('xxx'), // component to be loaded dynamically.
    	loading: <HoldingComponent /> // 预占位组件,动态组件未加载时显示loading信息等
    })
    
  3. 构建高可用的Loading组件——错误处理、避免占位信息和有效信息展示交替时的闪烁、加载超时、预加载、同时加载多个资源等;

    1. loader加载失败处理:失败时loading会接收到一个errorprop对象,否则为null

      function Loading(props) {
        if (props.error) {
          return <div>Error! <button onClick={ props.retry }>Retry</button></div>;
        } else {
          return <dxiv>Loading...</div>;
        }
      }
      
    2. Loadable支持设置设置一个默认的延迟时间,超过该时间才会显示loading;对应的Loadable属性为delay默认值为200ms,超过则loading的名为pastDelayproptrue

      Loadable({
      	loader: () => import('xxx')
      	loading: Loading,
      	delay: 300, // ms
      });
      
      const Loading = (props) => {
      	if (props.error) {
      		return <div>Woops! Error occured.<button onClick={props.retry}>Retry</button><div>
      	} else if (props.pastDelay) {
      		return <div>Loading...</div>
      	} else {
      		return null;
      	}
      };
      
    3. loader因网络问题等加载失败处理——Loadable支持设置timeout,默认被禁用;对应在loading组件中可以通过props.timeout属性获取状态,超时为true

      const LoadableSub = Loadable({
        loader: () => import("./Sub"),
        loading: Loading,
        delay: 500,
        timeout: 8000
      });
      const Loading = props => {
        if (props.error) {
          return <div>Woops, errors occurred!</div>;
        } else if (props.pastDelay) {
          return <div>Loading...</div>;
        } else if (props.timeOut) {
          return <div>Timeout, please retry</div>;
        } else {
          return null;
        }
      };
      
    4. 动态加载多个资源,可以使用Loadable.map({})

    5. Loadable支持预加载,单个组件的预加载使用方法类似于LoadableSub.preload()

    6. 客户端进行动态加载,可能会出现白屏等,所以如果SSR时能够对动态加载做一定的处理,那么可以优化该体验;

      This really sucks, but the good news is that React Loadable is designed to make server-side rendering work as if nothing is being loaded dynamically.

  4. 服务端渲染

    1. 确保渲染前对应的组件已加载就绪。预加载所有loadable component——使用Loadable.preloadAll,它返回一个promise对象,并且在所有loadable component就绪后resolve
      Loadable.preloadAll().then(() => {
        app.listen(3000, () => {
          console.log('Running on http://localhost:3000/');
        });
      });
      
    2. 客户端如何处理SSR APP
      a. 声明需要加载的模块,使用Loadableopt.moduleswebpack;另外,需要在babel配置中加入以下配置信息
      Loadable({
        loader: () => import('./Bar'),
        modules: ['./Bar'],
        webpack: () => [require.resolveWeak('./Bar')],
      });
      
      // babel配置
      {
        "plugins": [
          "react-loadable/babel"
        ]
      }
      
      b. 确定当某个请求完成后,哪些组件会被渲染;Loadable.Capture应运而生,可以记录已渲染的模块;
      import express from 'express';
      import React from 'react';
      import ReactDOMServer from 'react-dom/server';
      import App from './App';
      import Loadable from 'react-loadable';
      
      const app =  express();
      
      app.get('/', (req, res) => {
      	let modules = [];
      	
      	let html = ReactDOMServer.renderToString(
      		<Loadable.Capture report={moduleName => modules.push(moduleName)>
      			<App/>
      		</Loadable.Capture>
      	);
      	console.log({ modules });
      
      	res.end(`${html}`);
      });
      

参考文献
  1. jamiebuilds/react-loadable github
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值