关于 react-performance-optimizer
react-performance-optimizer 是帮助 React 开发者排查和改善性能问题的技能,提供分析渲染、列表、包体积和内存问题的策略。内容强调先用性能分析工具定位瓶颈,再选择虚拟化、代码拆分或记忆化等方案。
主要功能
- 01使用 Profiler 定位慢渲染
- 02大型列表虚拟化
- 03路由与组件代码拆分
- 04谨慎使用记忆化
- 05包体积分析与内存问题排查
适用场景
- 01诊断组件重复渲染和卡顿
- 02优化大量条目的列表滚动
- 03缩减首屏加载的 JavaScript 包
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ curiositech/ some_claude_skills --skill react-performance-optimizer安装后在 Claude Code 中输入/react-performance-optimizer确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
.claude-plugin/plugin.jsonreferences/bundle-optimization.mdmemory-leaks.mdprofiling-guide.mdscripts/bundle_analyzer.shperformance_audit.ts详细介绍
React 性能优化器
擅长诊断和修复 React 性能问题,打造流畅如丝的 60fps 体验。
适用场景
✅ 适用于:
- 组件重新渲染缓慢
- 大型列表(>100 项)导致卡顿
- Bundle 体积 >500KB(gzip 压缩后)
- 可交互时间 >3 秒
- 滚动或动画卡顿
- 组件卸载后出现内存泄漏
❌ 不适用于:
- 组件少于 10 个的应用(过早优化)
- 后端 API 响应缓慢(修复 API)
- 网络延迟(使用缓存/CDN)
- 非 React 框架(使用对应框架的工具)
快速决策树
Is your React app slow?
├── Profiler shows >16ms renders? → Use memoization
├── Lists with >100 items? → Use virtualization
├── Bundle size >500KB? → Code splitting
├── Lighthouse score <70? → Multiple optimizations
└── Feels fast enough? → Don't optimize yet
技术选型
性能工具(2024)
| 工具 | 用途 | 适用场景 |
|---|---|---|
| React DevTools Profiler | 找出缓慢的组件 | 始终从这里开始 |
| Lighthouse | 整体性能评分 | 前后对比 |
| webpack-bundle-analyzer | 找出体积较大的依赖项 | Bundle >500KB |
| why-did-you-render | 找出不必要的重新渲染 | 调试重新渲染风暴 |
| React Compiler(2024+) | 自动记忆化 | React 19+ |
时间线:
- 2018:推出 React.memo、useMemo、useCallback
- 2020:并发模式(现称并发渲染)
- 2022:React 18 中的自动批处理
- 2024:React Compiler(自动优化)
- 2025+:预计 React Compiler 将取代手动记忆化
常见反模式
反模式 1:过早记忆化
新手想法:“把所有内容都用 useMemo 包起来就能提速”
问题:收益微乎其微,却增加了复杂性和开销。
错误做法:
// ❌ Over-optimization
function UserCard({ user }) {
const fullName = useMemo(() => `${user.first} ${user.last}`, [user]);
const age = useMemo(() => new Date().getFullYear() - user.birthYear, [user]);
return <div>{fullName}, {age}</div>;
}
错误原因:字符串拼接比 useMemo 的开销更低。
正确做法:
// ✅ Simple is fast
function UserCard({ user }) {
const fullName = `${user.first} ${user.last}`;
const age = new Date().getFullYear() - user.birthYear;
return <div>{fullName}, {age}</div>;
}
经验法则:仅在以下情况下使用记忆化:
- 计算耗时 >5ms(使用 Profiler 测量)
- 结果会在依赖数组中使用
- 可以避免子组件重新渲染
反模式 2:不记忆化回调
问题:每次渲染都会创建新的函数实例,导致 React.memo 失效。
错误做法:
// ❌ Child re-renders on every parent render
function Parent() {
const [count, setCount] = useState(0);
return (
<Child onUpdate={() => setCount(count + 1)} />
);
}
const Child = React.memo(({ onUpdate }) => {
return <button onClick={onUpdate}>Update</button>;
});
错误原因:箭头函数会创建新的引用 → React.memo 形同虚设。
正确做法:
// ✅ Stable callback reference
function Parent() {
const [count, setCount] = useState(0);
const handleUpdate = useCallback(() => {
setCount(c => c + 1); // Updater function avoids dependency
}, []);
return <Child onUpdate={handleUpdate} />;
}
const Child = React.memo(({ onUpdate }) => {
return <button onClick={onUpdate}>Update</button>;
});
反模式 3:渲染大型列表时不使用虚拟化
问题:渲染 1000+ 个 DOM 节点会导致卡顿。
症状:滚动卡顿,首次渲染缓慢。
错误做法:
// ❌ Renders all 10,000 items
function UserList({ users }) {
return (
<div>
{users.map(user => (
<UserCard key={user.id} user={user} />
))}
</div>
);
}
正确做法:
// ✅ Only renders visible items
import { FixedSizeList } from 'react-window';
function UserList({ users }) {
return (
<FixedSizeList
height={600}
itemCount={users.length}
itemSize={50}
width="100%"
>
{({ index, style }) => (
<div style={style}>
<UserCard user={users[index]} />
</div>
)}
</FixedSizeList>
);
}
效果:10,000 个项目:渲染耗时从 5 秒降至 50ms。
反模式 4:不进行代码拆分
问题:一开始就下载 2MB 的 Bundle,导致初始加载缓慢。
错误做法:
// ❌ Everything in main bundle
import AdminPanel from './AdminPanel'; // 500KB
import Dashboard from './Dashboard';
import Settings from './Settings';
function App() {
return (
<Routes>
<Route path="/admin" element={<AdminPanel />} />
<Route path="/dashboard" element={<Dashboard />} />
<Route path="/settings" element={<Settings />} />
</Routes>
);
}
正确做法:
// ✅ Lazy load routes
import { lazy, Suspense } from 'react';
const AdminPanel = lazy(() => import('./AdminPanel'));
const Dashboard = lazy(() => import('./Dashboard'));
const Settings = lazy(() => import('./Settings'));
function App() {
return (
<Suspense fallback={<Loading />}>
<Routes>
<Route path="/admin" element={<AdminPanel />} />
<Route path="/dashboard" element={<Dashboard />} />
<Route path="/settings" element={<Settings />} />
</Routes>
</Suspense>
);
}
效果:初始 Bundle:从 2MB 降至 300KB。
反模式 5:在渲染过程中执行高开销操作
问题:每次渲染都会执行大量计算。
错误做法:
// ❌ Sorts on every render (even when data unchanged)
function ProductList({ products }) {
const sorted = products.sort((a, b) => b.price - a.price);
return <div>{sorted.map(p => <Product product={p} />)}</div>;
}
正确做法:
// ✅ Memoize expensive operation
function ProductList({ products }) {
const sorted = useMemo(
() => [...products].sort((a, b) => b.price - a.price),
[products]
);
return <div>{sorted.map(p => <Product product={p} />)}</div>;
}
实现模式
模式 1:使用 React.memo 处理纯组件
// Prevent re-render when props unchanged
const ExpensiveComponent = React.memo(({ data }) => {
// Complex rendering logic
return <div>{/* ... */}</div>;
});
// With custom comparison
const UserCard = React.memo(
({ user }) => <div>{user.name}</div>,
(prevProps, nextProps) => {
// Return true if props equal (skip re-render)
return prevProps.user.id === nextProps.user.id;
}
);
模式 2:使用 useMemo 执行高开销计算
function DataTable({ rows, columns }) {
const sortedAndFiltered = useMemo(() => {
console.log('Recomputing...'); // Only logs when rows/columns change
return rows
.filter(row => row.visible)
.sort((a, b) => a.timestamp - b.timestamp);
}, [rows, columns]);
return <Table data={sortedAndFiltered} />;
}
模式 3:使用 useCallback 保持引用稳定
function SearchBox({ onSearch }) {
const [query, setQuery] = useState('');
// Stable reference, doesn't break child memoization
const handleSubmit = useCallback(() => {
onSearch(query);
}, [query, onSearch]);
return (
<form onSubmit={handleSubmit}>
<input value={query} onChange={e => setQuery(e.target.value)} />
</form>
);
}
模式 4:虚拟化(react-window)
import { VariableSizeList } from 'react-window';
function MessageList({ messages }) {
const getItemSize = (index) => {
// Dynamic heights based on content
return messages[index].text.length > 100 ? 80 : 50;
};
return (
<VariableSizeList
height={600}
itemCount={messages.length}
itemSize={getItemSize}
width="100%"
>
{({ index, style }) => (
<div style={style}>
<Message message={messages[index]} />
</div>
)}
</VariableSizeList>
);
}
模式 5:使用 React.lazy 进行代码拆分
// Route-based splitting
const routes = [
{ path: '/home', component: lazy(() => import('./Home')) },
{ path: '/about', component: lazy(() => import('./About')) },
{ path: '/contact', component: lazy(() => import('./Contact')) }
];
// Component-based splitting
const HeavyChart = lazy(() => import('./HeavyChart'));
function Dashboard() {
const [showChart, setShowChart] = useState(false);
return (
<div>
<button onClick={() => setShowChart(true)}>Show Chart</button>
{showChart && (
<Suspense fallback={<Spinner />}>
<HeavyChart />
</Suspense>
)}
</div>
);
}
生产环境检查清单
□ Profiler analysis completed (identified slow components)
□ Large lists use virtualization (>100 items)
□ Routes code-split with React.lazy
□ Heavy components lazy-loaded
□ Callbacks memoized with useCallback
□ Expensive computations use useMemo
□ Pure components wrapped in React.memo
□ Bundle analyzed (no duplicate dependencies)
□ Tree-shaking enabled (ESM imports)
□ Images optimized and lazy-loaded
□ Lighthouse score >90
□ Time to Interactive <3 seconds
适用与不适用场景
| 场景 | 是否优化? |
|---|---|
| 渲染 1000+ 个列表项目 | ✅ 是 - 使用虚拟化 |
| 对大型数组排序/筛选 | ✅ 是 - 使用 useMemo |
| 向记忆化子组件传递回调 | ✅ 是 - 使用 useCallback |
| 字符串拼接 | ❌ 否 - 已足够快 |
| 简单算术运算 | ❌ 否 - 不要记忆化 |
| 10 项列表 | ❌ 否 - 过早优化 |
参考资料
/references/profiling-guide.md- React DevTools Profiler 使用方法/references/bundle-optimization.md- 缩减 Bundle 体积的策略/references/memory-leaks.md- 检测和修复内存泄漏
脚本
scripts/performance_audit.ts- 自动化性能检查scripts/bundle_analyzer.sh- 分析并可视化打包文件
此技能指南涵盖:React 性能优化 | 记忆化 | 虚拟化 | 代码拆分 | 打包文件优化 | 性能分析
评论
支持 Markdown