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