六、性能优化
6.1 按需引入详解
按需引入是 Arco Design 性能优化的核心手段,可以从打包体积中移除未使用的组件代码。
通过 babel-plugin-import 实现自动按需引入
npm install babel-plugin-import -D
// babel.config.js
module.exports = {
plugins: [
['import', {
libraryName: '@arco-design/web-react',
libraryDirectory: 'es',
camel2DashComponentName: false,
style: true, // 自动加载样式
}],
],
};
配置完成后,编写代码时只需:
import { Button, Input, Table } from '@arco-design/web-react';
// 插件会自动转换为:
// import Button from '@arco-design/web-react/es/button';
// import '@arco-design/web-react/es/button/style';
// import Input from '@arco-design/web-react/es/input';
// ...
从实际项目中验证优化效果
手动按需引入
如果不使用 babel 插件,也可以手动按需引入:
// ✅ 手动按需引入
import Button from '@arco-design/web-react/es/button';
import '@arco-design/web-react/es/button/style';
import Input from '@arco-design/web-react/es/input';
import '@arco-design/web-react/es/input/style';
6.2 图标按需引入优化
Arco Design 提供了独立的图标包 @arco-design/web-react/icon,包含超过 2000 个图标。全量引入图标库会显著增加打包体积。
// ❌ 错误:会引入所有图标
import * as Icons from '@arco-design/web-react/icon';
// ✅ 正确:只引入需要的图标
import { IconHome, IconUser, IconSettings } from '@arco-design/web-react/icon';
图标按需引入的打包效果对比:
使用动态图标的场景优化
当图标名称是动态的时,可以使用图标映射表:
// 预定义图标映射表
const iconMap = {
home: IconHome,
user: IconUser,
settings: IconSettings,
delete: IconDelete,
};
// 动态获取图标组件
const getIcon = (iconName) => {
return iconMap[iconName] || IconDefault;
};
// 使用
const DynamicIcon = getIcon('home');
<DynamicIcon />
6.3 路由懒加载与代码分割
结合 React Router 可以实现组件级别的懒加载:
import { lazy, Suspense } from 'react';
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import { Spin } from '@arco-design/web-react';
// 懒加载页面组件
const Dashboard = lazy(() => import('./pages/Dashboard'));
const UserList = lazy(() => import('./pages/UserList'));
const OrderList = lazy(() => import('./pages/OrderList'));
const Settings = lazy(() => import('./pages/Settings'));
function App() {
return (
<BrowserRouter>
<Suspense fallback={<Spin tip="加载中..." style={
{ marginTop: 100 }} />}>
<Routes>
<Route path="/" element={<Dashboard />} />
<Route path="/users" element={<UserList />} />
<Route path="/orders" element={<OrderList />} />
<Route path="/settings" element={<Settings />} />
</Routes>
</Suspense>
</BrowserRouter>
);
}
使用 Webpack 魔法注释自定义 chunk 名称:
const Dashboard = lazy(() => import(/* webpackChunkName: "dashboard" */ './pages/Dashboard'));
const UserList = lazy(() => import(/* webpackChunkName: "users" */ './pages/UserList'));
6.4 表格组件性能优化
对于大数据量表格,Arco Design 的 Table 组件提供了虚拟滚动(Virtual Scroll)功能,可以显著提升渲染性能。
import { Table } from '@arco-design/web-react';
// 生成大量测试数据
const generateLargeData = () => {
const data = [];
for (let i = 0; i < 10000; i++) {
data.push({
key: i,
name: `用户 ${i}`,
age: 20 + (i % 50),
address: `地址 ${i}`,
email: `user${i}@example.com`,
});
}
return data;
};
const columns = [
{ title: '姓名', dataIndex: 'name', width: 120, fixed: 'left' },
{ title: '年龄', dataIndex: 'age', width: 80 },
{ title: '地址', dataIndex: 'address', width: 200 },
{ title: '邮箱', dataIndex: 'email', width: 200, fixed: 'right' },
];
const VirtualTableDemo = () => {
const data = generateLargeData();
return (
<Table
columns={columns}
data={data}
virtualized
scroll={
{ y: 500, x: 800 }}
pagination={false}
border
/>
);
};
虚拟滚动的性能优势:
6.5 Tree Shaking 优化原理
Arco Design 使用 ES Modules 格式导出,支持 Webpack、Rollup、Vite 等构建工具的 Tree Shaking。确保以下几点以获得最佳优化效果:
使用 ES Module 引入方式:
// ✅ 好的做法
import { Button } from '@arco-design/web-react';
// ❌ 不好的做法(会阻止 Tree Shaking)
import Arco from '@arco-design/web-react';
const { Button } = Arco;
确保 sideEffects 配置正确:
// package.json 中确保 sideEffects 配置包含样式文件
{
"sideEffects": [
"*.css",
"*.less"
]
}
使用 Webpack Bundle Analyzer 分析打包结果:
npm install webpack-bundle-analyzer -D
// webpack.config.js
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = {
plugins: [
new BundleAnalyzerPlugin(),
],
};
6.6 使用 React.memo 减少不必要的重渲染
对于频繁渲染的组件,使用 React.memo 可以避免不必要的重渲染:
import { memo } from 'react';
import { Card, Button } from '@arco-design/web-react';
const UserCard = memo(({ user, onEdit }) => {
console.log('UserCard rendered:', user.id);
return (
<Card>
<div>姓名:{user.name}</div>
<div>年龄:{user.age}</div>
<Button onClick={() => onEdit(user.id)}>编辑</Button>
</Card>
);
});
6.7 使用 useMemo / useCallback 缓存计算结果
import { useMemo, useCallback, useState } from 'react';
import { Table, Input } from '@arco-design/web-react';
function UserList({ users }) {
const [keyword, setKeyword] = useState('');
// 缓存过滤后的用户列表
const filteredUsers = useMemo(() => {
if (!keyword) return users;
return users.filter(user =>
user.name.includes(keyword) || user.email.includes(keyword)
);
}, [users, keyword]);
// 缓存事件处理函数
const handleSearch = useCallback((value) => {
setKeyword(value);
}, []);
return (
<>
<Input.Search onSearch={handleSearch} placeholder="搜索用户" />
<Table data={filteredUsers} columns={columns} />
</>
);
}
6.8 性能监控与调试
在 React 18+ 中,使用 React DevTools 的 Profiler 可以分析组件渲染性能:
import { Profiler } from 'react';
function onRenderCallback(
id, // 这次提交的 Profiler 树的 id
phase, // "mount" 或 "update"
actualDuration, // 本次更新渲染耗时
) {
console.log(`${id} 渲染耗时: ${actualDuration}ms`);
}
function App() {
return (
<Profiler id="UserList" onRender={onRenderCallback}>
<UserList />
</Profiler>
);
}