zoukankan      html  css  js  c++  java
  • React 入门(7): 动态加载组件

    import()异步加载模块

    在webpack中, 调用import()函数可以将依赖模块进行切割, 打包为非入口点文件, 这是通过Promise+ajax完成的. 请求路径是相对路径, 对于单页应用来说没有问题.
    非入口点文件的命名由webpack.config.output.chunkFilename(可以定义路径, 使用[name]和[id]变量)以及Magic Comment(定义[name]变量)共同确定.

    React.lazy()函数

    React.lazy() 允许你定义一个动态加载的组件。这有助于缩减 bundle 的体积,并延迟加载在初次渲染时未用到的组件。

    // 这个组件是动态加载的
    const SomeComponent = React.lazy(() => import('./SomeComponent'));
    

    渲染 lazy 组件依赖该组件渲染树上层的 <React.Suspense> 组件。这是指定加载指示器(loading indicator)的方式。
    使用 React.lazy 的动态引入特性需要 JS 环境支持 Promise。在 IE11 及以下版本的浏览器中需要通过引入 polyfill 来使用该特性。

    ! 不支持服务端渲染。

    例子 -- lazy加载组件

    import { Component, lazy, Suspense } from 'react';
    import css from './style.css';
    
    /** 异步组件使用lazy()函数加载, 传递一个使用import()函数的Promise异步方法, 该方法最终返回import()函数的结果 */
    const AsyncComponent = lazy(() => {
        return new Promise((resolve, reject) => {
            import('./AsyncComponent').then(AsyncComponent => {
                console.log('加载完毕, 延迟传送');
                setTimeout(() => {
                    console.log('传送');
                    resolve(AsyncComponent);
                }, 5000);
            });
        });
    });
    
    export default (
        <div id={css.app}>
            <Suspense fallback={<h1>加载中</h1>}>
                <AsyncComponent></AsyncComponent>
            </Suspense>
        </div>
    );
    

    Suspense组件

    React关注DOM和事件, 数据更新更是重要, 因此, 我们来看Suspense组件如何在异步操作与UI更新之间建起桥梁.

    代码分割: https://zh-hans.reactjs.org/docs/code-splitting.html#reactlazy
    Suspense: https://zh-hans.reactjs.org/docs/concurrent-mode-suspense.html
    Suspense还用于异步数据的获取:
    官方示例: https://codesandbox.io/s/frosty-hermann-bztrp?file=/src/fakeApi.js

    抛出Promise: 使用throw关键字陷入React内核

    在执行异步操作的过程中, 我们只需要在Promise未完成状态时将该Promise抛出到React核心即可:

    function fetchName() {
        console.log('尝试联网获取用户名...');
        throw new Promise(()=> {
            console.log('抛出一个永久pending状态的Promise');
        });
    }
    
    function FunctionComponent(props) {
        console.log('尝试获取用户名并渲染UI...');
        return <h2>用户名: {fetchName()}</h2>
    }
    
    export default (
        <div id={css.app}>
            <Suspense fallback={<h1>正在联网获取用户名...</h1>}>
                <FunctionComponent/>
            </Suspense>
        </div>
    );
    

    Promise的拒绝状态会导致组件立即重新渲染, 并可能不断重复:

    function fetchName() {
        console.log('尝试联网获取用户名...');
        throw new Promise((_, reject)=> {
            console.log('抛出一个拒绝状态的Promise');
            reject();
        });
    }
    

    抛出其它非Promise异常会被React重新抛出, 导致页面报错.
    如果一个抛出的Promise结束了成为success状态, 那么它之后应该返回相应的结果, 而不是再次抛出Promise, 因为success状态的Promise(这里可能是全部的Promise结束后再调用)会导致方法组件再次被调用以渲染元素.

    import { Component, lazy, Suspense, createElement, useRef } from 'react';
    import css from './style.css';
    
    // 单例
     let fetchNameByInternet = () => new Promise(resolve => {
         console.log('网络请求开始了, 将于4秒后完成');
         setTimeout(() => resolve('develon'), 4000);
     });
    
    let resolved = false; // 标志网络请求是否已完成
    let name = "Don't get the Name"; // 存储从网络获取的用户名
    
    function fetchName() {
        console.log('尝试联网获取用户名...');
        if (resolved) {
            console.log(`获取到数据: "${name}" !`);
            return name;
        }
        throw fetchNameByInternet().then(network_name => {
            resolved = true;
            name = network_name;
        });
    }
    
    function FunctionComponent(props) {
        console.log('方法组件被调用, 尝试获取用户名并渲染UI...');
        let name = fetchName(); // 此处会抛出异常, 不可进行捕获, 从而就像CPU中断指令一样陷入React内核
        console.log('方法组件继续执行, 开始渲染元素'); // 整个方法结束, 只有当Promise成功之后, 才会再次调用该方法组件, 所以说这些异步操作是有顺序的
        return <h2>用户名: {name}</h2>;
    }
    
    export default (
        <div id={css.app}>
            <Suspense fallback={<h1>正在联网获取用户名...</h1>}>
                <FunctionComponent/>
            </Suspense>
        </div>
    );
    

    END

  • 相关阅读:
    linux启动流程
    控制nginx并发链接数量和客户端请求nginx的速率
    MySQL修改密码
    nginx站点目录及文件URL访问控制
    nginx日志相关优化安全
    根据参数优化nginx的服务性能
    nginx基本安全优化
    nginx rewrite
    nginx location
    nginx访问日志(access_log)
  • 原文地址:https://www.cnblogs.com/develon/p/13706136.html
Copyright © 2011-2022 走看看