@ozo/lazy-loader

lazy loader for React

环境

  • React v16.3+
  • webpack 4.6+

Install

npm install @ozo/lazy-loader

API

该库可用于动态加载 React 组件或其他工具库。

React 组件动态导入,支持自定义加载动画

  • @param {Function} func 返回动态引入的函数, 如 ()=>import('./a/b/c')
  • @param {Function} spinner 加载的的 loading, 默认为 loadSpinner
  • @returns {Component} React 组件

采用 React 原生的 Suspense,lazy 实现 lazyload

lazy (function, spinner)

React.lazy 的具体用法:https://reactjs.org/docs/code-splitting.html#reactlazy

采用@loadable/component 组件实现

  • lazyX (function, spinner)
  • loadable (function, spinner)
  • loadableDelay (promise, delay = 200, spinner) :支持延时加载
  • loadableTimeout (promise, time = 5000, spinner) :支持加载超时

lib 动态导入

可以延迟加载指定库,当库加载完后需要通过 render props called 或 ref 来取值。

  • @param {Function} func 返回动态引入的函数, 如 ()=>import('./a/b/c')
  • @returns {Component} React 组件

  • lazyLib (func):需要采用包裹。
const Moment = lazyLib(() => import("moment"));

function FromNow({ date }) {
  return (
    <Suspense fallback={<div>loading</div>}>
      <Moment fallback={date.toLocaleDateString()}>
        {({ default: moment }) => moment(date).fromNow()}
      </Moment>
    </Suspense>
  );
}

<FromNow date={new Date()} />;

@loadable/component 支持服务端渲染,具体用法请参考:https://www.smooth-code.com/open-source/loadable-components/

React.lazy 和@loadable/component 组件的区别

https://www.smooth-code.com/open-source/loadable-components/docs/loadable-vs-react-lazy/

webpack 的 动态导入特性

Magic Comments:https://webpack.js.org/api/module-methods/#magic-comments

扩展使用

利用 loadable 进一步封装

利用 loadable 进一步封装生成 AsyncLoad 组件,通过组件方式加载,可以避免繁琐的变量定义。适合在项目本地封装使用,例如路由统一配置表中(统一引入路径),注意使用场景及组件的路径匹配。

// ./src/App.js

import { loadable } from "@ozo/lazy-loader";

// 动态加载组件的组件,支持自定义加载动画
const AsyncLoad = loadable(({ path }) => import(path));

function MyComponent() {
  return (
    <div>
      <AsyncLoad path="./Home" />
      <AsyncLoad path="./Contact" />
    </div>
  );
}

import()中的相对路径相对于 import 语句所在的文件,无法通过工具包进一步封装。

Simple Usage

import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import styled from 'styled-components';
import { lazy, lazyX, loadable, loadableDelay, loadableTimeout } from '@ozo/lazy-loader';
import Loader from 'react-loader-spinner';
import 'react-loader-spinner/dist/loader/css/react-spinner-loader.css';
import NormalLoad from './Demo.jsx';

const LazyLoad = lazy(() => import('./Demo'), { pastDelay: 0 });
const LazyXLoad = lazyX(() => import('./Demo'));
/**
 * 动态加载组件的组件,支持自定义加载动画
 */
const AsyncLoad = loadable(() => import('./Demo'));
const PreLoad = loadable(() => import('./Demo'));
const DelayLoad = loadableDelay(import('./Demo'), {
    delay: 3000,
    spinner: <Loader type="Triangle" color="#666" height={50} width={50} />,
});
const TimeoutLoad = loadableTimeout(import('./Demo'), { timeout: 5 });

async function randomString(len) {
    len = len || 16;
    // 默认去掉了容易混淆的字符oOLl,9gq,Vv,Uu,I1
    var $chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678';
    var maxPos = $chars.length;
    var pwd = '';

    for (let i = 0; i < len; i++) {
        pwd += $chars.charAt(Math.floor(Math.random() * maxPos));
    }
    return pwd;
}

const Section = styled.div`
    overflow: hidden;
`;

class App extends Component {
    state = {
        list: [],
    }
    componentDidMount(){
        const list = await randomString(480000).split('');

        setTimeout(()=>{
            this.setState({list: list});
        }, 0);
    }
    render() {
        const { list } = this.state;
        PreLoad.preload();
        return (
            <>                
                <Section>
                    <h3>使用loadable预加载</h3>
                    <AsyncLoad list={list} />
                </Section>                
            </>
        );
    }
}

ReactDOM.render(<App />, mountNode);