mcpField
R
react-performance

react-performance

github.com/s-hiraoku开发1992 次安装4 周前更新
代码仓库

关于 react-performance

面向 React 和 Next.js 应用的性能优化技能,按影响程度组织建议,涵盖数据瀑布、包体积、服务端工作、重复渲染和渲染开销。

主要功能

  1. 01按优先级组织优化建议
  2. 02减少串行数据请求
  3. 03优化包体积与导入
  4. 04服务端性能技巧
  5. 05改善重复渲染与页面渲染

适用场景

  1. 01查找 React 页面中的串行请求
  2. 02缩减初始包体积
  3. 03避免服务端重复请求数据
  4. 04改善长列表渲染

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/s-hiraoku/synapse-a2a --skill react-performance

安装后在 Claude Code 中输入/react-performance确认已加载。

详细介绍

React 性能

针对 React 和 Next.js 应用的系统化性能优化,按影响程度排序。

优先级 1:消除瀑布流(严重)

顺序执行的异步操作是最大的性能杀手。请先修复这些问题。

延迟等待

在实际使用时再执行 await,而不是在声明时执行。

// BAD: Sequential — total time = fetch1 + fetch2
async function Page() {
  const user = await getUser();
  const posts = await getPosts(user.id);
  return <Feed user={user} posts={posts} />;
}

// GOOD: Parallel where possible
async function Page() {
  const userPromise = getUser();
  const postsPromise = getPosts(); // if independent
  const [user, posts] = await Promise.all([userPromise, postsPromise]);
  return <Feed user={user} posts={posts} />;
}
Suspense 流式传输

使用 <Suspense> 包裹耗时的数据操作,让页面外壳立即渲染。

export default function Page() {
  return (
    <main>
      <Header />              {/* instant */}
      <Suspense fallback={<Skeleton />}>
        <SlowDataSection />   {/* streams in */}
      </Suspense>
    </main>
  );
}
部分依赖

当 Promise 之间存在部分依赖时,立即启动相互独立的操作。

async function Dashboard() {
  const userPromise = getUser();
  const settingsPromise = getSettings(); // independent

  const user = await userPromise;
  const postsPromise = getPosts(user.id); // depends on user

  const [settings, posts] = await Promise.all([settingsPromise, postsPromise]);
  return <View user={user} settings={settings} posts={posts} />;
}

优先级 2:包体积(严重)

直接导入

生产代码中绝不要从汇总文件导入。

// BAD: Pulls entire library
import { Button } from '@/components';
import { format } from 'date-fns';

// GOOD: Tree-shakeable
import { Button } from '@/components/ui/button';
import { format } from 'date-fns/format';
动态导入

对初次渲染时不需要的重量级组件进行代码拆分。

import dynamic from 'next/dynamic';

const Chart = dynamic(() => import('@/components/chart'), {
  loading: () => <ChartSkeleton />,
  ssr: false,  // skip SSR for client-only components
});

const Editor = dynamic(() => import('@/components/editor'), {
  loading: () => <EditorSkeleton />,
});
延迟加载第三方脚本

在 hydration 后加载分析、日志记录和非关键脚本。

// BAD: Blocks hydration
import { analytics } from 'heavy-analytics';
analytics.init();

// GOOD: Load after hydration
useEffect(() => {
  import('heavy-analytics').then(({ analytics }) => analytics.init());
}, []);
按意图预加载

在用户表现出意图时(悬停、聚焦)预加载资源。

function NavLink({ href, children }: { href: string; children: React.ReactNode }) {
  const router = useRouter();
  return (
    <Link
      href={href}
      onMouseEnter={() => router.prefetch(href)}
      onFocus={() => router.prefetch(href)}
    >
      {children}
    </Link>
  );
}

优先级 3:服务端性能(高)

请求范围内去重

使用 React.cache() 在单个请求内对数据获取进行去重。

import { cache } from 'react';

export const getUser = cache(async (id: string) => {
  return db.user.findUnique({ where: { id } });
});

// Called in layout.tsx AND page.tsx — only one DB query
尽量减少序列化

只传递客户端组件实际需要的数据。

// BAD: Serializes entire user object
<ClientAvatar user={user} />

// GOOD: Pass only what's needed
<ClientAvatar name={user.name} avatarUrl={user.avatarUrl} />
非阻塞后台工作

对于不应阻塞响应的工作,使用 after()。

import { after } from 'next/server';

export async function POST(request: Request) {
  const data = await processRequest(request);

  after(async () => {
    await logAnalytics(data);
    await sendNotification(data);
  });

  return Response.json(data); // returns immediately
}

优先级 4:避免重新渲染(中)

派生状态

在渲染期间计算派生值,绝不要在 effect 中计算。

// BAD: Extra render cycle
const [items, setItems] = useState([]);
const [count, setCount] = useState(0);
useEffect(() => setCount(items.length), [items]);

// GOOD: Derive during render
const [items, setItems] = useState([]);
const count = items.length;
稳定引用

使用基于回调的 setState,并将回调提取到渲染函数之外。

// BAD: New function every render
<Button onClick={() => setCount(count + 1)} />

// GOOD: Stable reference
<Button onClick={() => setCount(c => c + 1)} />
基本类型依赖项

在依赖项数组中使用基本类型,以避免误报。

// BAD: Object reference changes every render
useEffect(() => { ... }, [config]);

// GOOD: Primitive values are stable
useEffect(() => { ... }, [config.apiUrl, config.timeout]);
惰性状态初始化

为开销较大的初始状态传入初始化函数。

// BAD: Runs every render
const [data, setData] = useState(expensiveParse(raw));

// GOOD: Runs only on mount
const [data, setData] = useState(() => expensiveParse(raw));
记忆化开销较大的组件

将繁重的计算提取到经过记忆化的子组件中。

const ExpensiveList = memo(function ExpensiveList({ items }: { items: Item[] }) {
  return items.map(item => <ComplexItem key={item.id} item={item} />);
});
使用 useTransition 处理可延迟更新

使用 startTransition 处理非紧急状态更新。

const [isPending, startTransition] = useTransition();

function handleSearch(query: string) {
  setInputValue(query);                    // urgent: update input
  startTransition(() => setResults(search(query))); // deferrable: update results
}

优先级 5:渲染性能(低至中)

内容可见性

为较长的可滚动列表应用 CSS content-visibility。

.list-item {
  content-visibility: auto;
  contain-intrinsic-size: 0 80px;
}
提升静态 JSX

将不依赖 props/state 的 JSX 提取到组件之外。

// BAD: Recreated every render
function Layout({ children }) {
  return (
    <div>
      <footer><p>Copyright 2026</p></footer>
      {children}
    </div>
  );
}

// GOOD: Created once
const footer = <footer><p>Copyright 2026</p></footer>;
function Layout({ children }) {
  return <div>{footer}{children}</div>;
}
条件渲染

优先使用三元表达式而非 &&,以避免渲染 0 或 ""。

// BAD: Renders "0" when count is 0
{count && <Badge count={count} />}

// GOOD: Explicit boolean check
{count > 0 ? <Badge count={count} /> : null}

快速参考

问题修复方法优先级
顺序获取数据Promise.all() / Suspense严重
汇总文件导入直接按路径导入严重
初始包体积过大next/dynamic严重
冗余数据库调用React.cache()高
序列化过多的 props仅传递基本类型高
在 useEffect 中使用派生状态在渲染期间计算中
不稳定的回调useCallback / 回调式 setState中
长列表虚拟化 + content-visibility中
非紧急更新useTransition中

评论

支持 Markdown