React教程(十三) : 性能优化 - Lazy, suspense & package size

由于篇幅原因,再开一个性能优化的帖子,讲一下怎么做lazy loading和code split
先介绍一个VS Code插件,可以查看import package的大小。 插件名:Import Cost

import React, { Suspense, lazy } from 'react';
import { BrowserRouter as Router, Route, Switch, Link } from 'react-router-dom';
const Home = lazy(() => import('./Home'));
const About = lazy(() => import('./About'));

const LazyDemo = () => {
    return (
        <Router>
            <Suspense fallback={<div>Loading...</div>}>
                <ul>
                    <li><Link to='/'>Home</Link></li>
                    <li><Link to='/about'>About</Link></li>
                </ul>
                <Switch>
                    <Route exact path="/" component={Home} />
                    <Route path="/about" component={About} />
                </Switch>
            </Suspense>
        </Router>
    )
}

export default LazyDemo;

以上代码示例说明了Lazy + Suspense是如何工作的。

代码示例见:https://github.com/992990831/modernization/tree/main/performance-tuning

这个示例非常简单,但有个小问题。 其中的Home、About组件会被webpack独立打包(code split),但由于其非常小,Loading效果根本看不出。 怎么才能设置最小loading时间呢?
答:Lazy中的import返回的是Promise对象,我们可以通过增加一个并行运行的Promise,为该Promise设置最小返回时间,来实现最小loading时间的效果。代码如下:

const Home = lazy(() => import('./Home'));
//const About = lazy(() => import('./About'));
const About = lazy(() => {
    return Promise.all([
      import("./Home"),
      new Promise(resolve => setTimeout(resolve, 3000)) //增加三秒延迟
    ])
    .then(([moduleExports]) => moduleExports);
  });

参考:https://stackoverflow.com/questions/54158994/react-suspense-lazy-delay

上述代码是通过路由(Router)实现延迟加载+代码拆分。 下面的示例演示了怎么在代码中实现lazy。


import React, { Suspense, lazy, useState } from 'react';

const data = [1, 2, 3, 4, 5, 6];

const DynamicLazyDemo = () => {
    const [lazyComponent, setLazyComponent] = useState(<></>);

    async function loadComponent(id: number) {
        // const LazyDemo = await lazy(() =>
        //     import(`./SubComponent${id}`)
        //         .catch(() => console.log('Error in importing'))
        // );
        const LazyDemo = await lazy( () => {
            return Promise.all([
                import(`./SubComponent${id}`),
                new Promise(resolve => setTimeout(resolve, 2000))
            ]).then(([moduleExports]) => moduleExports);
        })

        setLazyComponent(<LazyDemo key={id}></LazyDemo>);
    }

    return (
        <>
            {
                data.map(d => {
                    return (
                        <input key={d} type='button' value={`load comopent-${d}`} onClick={() => loadComponent(d)} style={{ marginLeft: '1em' }}></input>
                    );
                })
            }

            <Suspense fallback={<div>延迟2秒加载中</div>}>
                {
                    lazyComponent
                }
            </Suspense>

        </>
    )
}

export default DynamicLazyDemo;

上述代码的运行效果是:出现6个按钮,每个按钮click后,加载对应的子组件。

CRA框架会根据lazy代码中的import部分,把对应组件单独打包:

完整的代码示例:https://github.com/992990831/modernization/tree/main/performance-tuning

posted @   老胡Andy  阅读(298)  评论(0编辑  收藏  举报
编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示