mcpField
R
react-expert

react-expert

github.com/oimiragieo开发4468 次安装17 周前更新
代码仓库

关于 react-expert

面向 React 开发者的指导技能,适用于代码审查和界面构建,涵盖 Hooks、组件架构、React 19、性能、表单、测试与无障碍设计。

主要功能

  1. 01审查 React 代码与模式
  2. 02应用 React 19 API 和 Actions
  3. 03设计组件与状态管理
  4. 04指导性能优化和数据获取
  5. 05处理测试与无障碍设计

适用场景

  1. 01审查组件的 Hooks 使用与模式
  2. 02规划 React 19 表单流程
  3. 03检查界面的无障碍问题

安装

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

$npx skills add https://github.com/oimiragieo/agent-studio --skill react-expert

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

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

commands/
react-expert.md
hooks/
post-execute.cjs
pre-execute.cjs
references/
research-requirements.md
rules/
react-expert.md
schemas/
input.schema.json
output.schema.json
scripts/
main.cjs
templates/
implementation-template.md

详细介绍

React 专家

React 生态系统专家,深入了解 hooks、状态管理、组件模式、React 19 特性、Shadcn UI 和 Radix 原语。 - 审查代码是否符合 React 最佳实践 - 实现现代 React 模式(React 19) - 设计组件架构 - 优化 React 性能 - 使用 Radix/Shadcn 构建无障碍 UI

组件结构

  • 使用函数组件,而非类组件
  • 保持组件小巧且专注
  • 将可复用逻辑提取到自定义 hooks 中
  • 优先使用组合,而非继承
  • 使用 TypeScript 实现恰当的 props 类型
  • 将大型组件拆分为更小、更专注的组件

Hooks

  • 遵循 Hooks 规则
  • 使用自定义 hooks 实现可复用逻辑
  • 保持 hooks 专注且简单
  • 在 useEffect 中使用恰当的依赖数组
  • 必要时在 useEffect 中实现清理
  • 避免嵌套使用 hooks

状态管理

  • 使用 useState 管理组件本地状态
  • 使用 useReducer 实现复杂状态逻辑
  • 使用 Context API 管理共享状态
  • 尽可能让状态靠近其使用位置
  • 通过恰当的状态管理避免逐层传递 props
  • 仅在必要时使用状态管理库

性能

  • 使用 React Compiler(React 19 中提供)实现自动记忆化——当编译器能够推断时,移除手动添加的 useMemo/useCallback
  • 仅当编译器无法胜任时才添加 React.memo、useMemo、useCallback(例如复杂的对象标识、外部依赖项、第三方库所需的稳定回调引用)
  • 避免不必要的重复渲染;添加手动记忆化前,先使用 React DevTools Profiler 验证
  • 使用 React.lazy 和 Suspense 实现恰当的延迟加载
  • 为列表设置恰当的 key props
  • 保持组件小巧且专注——小型组件能最大限度地扩大编译器的优化范围

React 19 特性

React Compiler
  • React Compiler(在 React 19 中稳定)会在构建时执行自动记忆化
  • 移除多余的 React.memo、useMemo、useCallback 封装——编译器会处理这些工作
  • 退出编译器优化:在需要手动控制的组件/文件中添加 // @no-react-compiler 编译指示
  • 以下情况仍使用 useMemo/useCallback:传递给第三方库的稳定引用;编译器无法识别外部依赖项的高开销计算
Actions
  • 将异步函数用作表单的 action props,以自动管理待处理和错误状态
  • Actions 取代了 onSubmit 加手动加载/错误状态的样板模式
  • Server Actions(在 Next.js / RSC 框架中)允许从表单直接调用服务器端代码
// Form Action pattern (React 19)
async function saveUser(formData: FormData) {
  'use server'; // only in RSC frameworks; omit for client Actions
  await db.users.update({ name: formData.get('name') });
}
<form action={saveUser}>
  <input name="name" />
  <button type="submit">Save</button>
</form>;
useActionState
  • 使用 useActionState 跟踪表单 Action 的结果和待处理状态
  • 函数签名:const [state, formAction, isPending] = useActionState(fn, initialState)
  • isPending 可取代手动使用 useState(false) 设置加载标记的模式
  • state 保存上一次 Action 调用的返回值(成功数据或错误)
import { useActionState } from 'react';

async function submitAction(prevState: State, formData: FormData) {
  const result = await saveData(formData);
  return result.error ? { error: result.error } : { success: true };
}

function MyForm() {
  const [state, formAction, isPending] = useActionState(submitAction, null);
  return (
    <form action={formAction}>
      {state?.error && <p>{state.error}</p>}
      <button disabled={isPending}>{isPending ? 'Saving...' : 'Save'}</button>
    </form>
  );
}
useOptimistic
  • 使用 useOptimistic 在服务器响应到达前即时反馈 UI
  • 函数签名:const [optimisticState, setOptimistic] = useOptimistic(value, reducer?)
  • Action 结束后,乐观值会自动恢复为真实值
  • 始终与 Actions 配合使用(乐观状态的生命周期受 Action 限定)
import { useOptimistic } from 'react';

function ItemList({ items, addItem }: Props) {
  const [optimisticItems, addOptimistic] = useOptimistic(items, (state, newItem) => [
    ...state,
    { ...newItem, pending: true },
  ]);
  async function action(formData: FormData) {
    const newItem = { text: formData.get('text') as string, id: crypto.randomUUID() };
    addOptimistic(newItem);
    await addItem(newItem);
  }
  return (
    <ul>
      {optimisticItems.map(item => (
        <li key={item.id} className={item.pending ? 'opacity-50' : ''}>
          {item.text}
        </li>
      ))}
      <form action={action}>
        <input name="text" />
        <button>Add</button>
      </form>
    </ul>
  );
}
use() hook
  • use(promise)——在渲染期间读取 Promise 已解析的值(与 Suspense/ErrorBoundary 集成)
  • use(Context)——取代 useContext;可以有条件地调用(其他 hooks 则不可以)
  • 与 useEffect 不同,use(promise) 不会在每次渲染时创建新的 Promise;请传入稳定的 Promise
  • 当需要有条件地使用 context 或在循环中使用 context 时,使用 use(Context)
import { use } from 'react';

// Reading context conditionally (not possible with useContext)
function Component({ show }: { show: boolean }) {
  if (!show) return null;
  const theme = use(ThemeContext); // valid — use() can be called conditionally
  return <div className={theme.bg}>...</div>;
}

// Reading a promise (wrap in Suspense + ErrorBoundary)
function UserProfile({ userPromise }: { userPromise: Promise<User> }) {
  const user = use(userPromise); // suspends until resolved
  return <p>{user.name}</p>;
}
其他 React 19 API 变更
  • ref 现在是普通 prop — 无需 forwardRef 包装(function Input({ ref }) { ... })
  • useFormStatus — 读取最近父级 <form> Action 的待处理/错误状态
  • 文档元数据 API:可在组件树的任意位置渲染 <title>、<meta>、<link>;React 会将它们提升到 <head>
  • React 19 中,startTransition 支持异步函数(Transitions)
  • useDeferredValue 现在接受 initialValue 参数,用于 SSR 水合
  • useId 在服务端组件中保持稳定;可用于无障碍 ID(label htmlFor / aria-labelledby)

React Server Components(RSC)

RSC 是一种架构边界,而非优化开关。放置组件前,先了解两者的划分。

组件分类规则
  • Server Component(Next.js App Router 中的默认类型): 不使用 useState、useEffect、事件处理程序或浏览器 API — 仅在服务端渲染,不会发送客户端 JS
  • Client Component('use client' 指令): 可交互,使用 Hooks、事件处理程序和浏览器 API — 在浏览器中进行水合
  • 在文件顶部将组件标记为 'use client';该边界以下的所有导入也都属于客户端
数据获取模式
  • 在 Server Components 中直接使用 async/await 获取数据 — 无需 useEffect,也无需编写加载状态样板代码
  • 将数据获取逻辑与需要数据的组件放在一起(避免逐层传递获取的数据)
// Server Component — fetch directly, no useEffect
async function UserCard({ userId }: { userId: string }) {
  const user = await db.users.findById(userId); // direct DB / API call
  return <div>{user.name}</div>;
}

// Client Component — interactive leaf
('use client');
function LikeButton({ postId }: { postId: string }) {
  const [liked, setLiked] = useState(false);
  return <button onClick={() => setLiked(l => !l)}>{liked ? 'Unlike' : 'Like'}</button>;
}
组合边界规则
  • Server Components 可以渲染 Client Components
  • Client Components 不能直接导入 Server Components — 应将 Server Components 作为 children prop 传入
  • 尽量让 Client Components 保持为小型叶子节点;将数据获取逻辑上移到 Server Components 中
// WRONG: importing a Server Component inside a Client Component
'use client'
import { ServerComp } from './ServerComp' // breaks — ServerComp would be bundled client-side

// CORRECT: pass as children prop
'use client'
function ClientShell({ children }: { children: React.ReactNode }) {
  return <div onClick={...}>{children}</div>
}
// In a Server Component parent:
<ClientShell><ServerComp /></ClientShell>
缓存与重新验证(Next.js App Router)
  • 在 Server Actions 中使用 revalidatePath / revalidateTag,在变更后清除缓存
  • 使用 React 的 cache() 在单次渲染过程中去重请求
  • 避免过度缓存:对于用户专属或实时数据,使用 { cache: 'no-store' } 获取
不适合使用 RSC 的情况
  • 高度交互的组件(模态框、拖放、实时交互)— 使用 Client Components
  • 依赖 Web API(localStorage、geolocation、canvas)的组件 — 使用 Client Components
  • 使用 RSC 会增加复杂度却无法减小 bundle 体积时 — 不要强行采用此模式

Radix UI 与 Shadcn

  • 按照文档实现 Radix UI 组件
  • 遵循所有组件的无障碍指南
  • 使用 Shadcn UI 的样式约定
  • 组合基础组件来构建复杂组件

表单

  • 优先使用 React 19 Actions(<form> 上的 action prop),而不是手动编写 onSubmit + useState 加载样板代码
  • 使用 useActionState 跟踪表单 Actions 的待处理、错误和结果状态
  • 在子组件中使用 useFormStatus 读取外层表单的待处理状态
  • 使用 useOptimistic 在异步提交期间提供即时反馈
  • 需要精细验证或字符级反馈时,改用受控组件(value + onChange)
  • 复杂的多步骤表单需要模式验证时,使用表单库(React Hook Form、Zod)
  • 实现适当的无障碍支持:使用 htmlFor 关联标签,通过 aria-describedby 关联错误消息,并在出错时管理焦点

错误处理

  • 实现错误边界
  • 正确处理异步错误
  • 显示用户友好的错误消息
  • 实现适当的回退 UI
  • 适当地记录错误

测试

  • 为组件编写单元测试
  • 为复杂流程编写集成测试
  • 使用 React Testing Library
  • 测试用户交互
  • 测试错误场景

无障碍

  • 使用语义化 HTML 元素
  • 设置适当的 ARIA 属性
  • 确保支持键盘导航
  • 使用屏幕阅读器进行测试
  • 管理焦点
  • 为图片提供适当的替代文本

模板

验证

forbidden_patterns: - pattern: "useEffect\\([^)]*\\[\\]\\s*\\)" message: "空依赖数组可能导致闭包过时" severity: "warning" - pattern: "dangerouslySetInnerHTML" message: "避免使用 dangerouslySetInnerHTML;如有必要,请先进行清理" severity: "warning" - pattern: "document\\.(getElementById|querySelector)" message: "请使用 React refs 代替直接访问 DOM" severity: "warning" - pattern: "forwardRef" message: "React 19:将 ref 作为普通 prop 传递,而不要使用 forwardRef" severity: "info" - pattern: "import.*useContext.*from 'react'" message: "React 19:优先使用 use(Context),它支持条件调用" severity: "info" **组件审查**: ``` User: "Review this React component for best practices" Agent: [Analyzes hooks, memoization, accessibility, and provides feedback] ``` ## 铁律
  1. 始终使用带 Hooks 的函数组件——类组件属于旧代码,与 React Compiler、Server Components 和未来的并发功能不兼容。
  2. 绝不违反 Hooks 规则——Hooks 必须始终在组件顶层调用,不能在条件语句、循环或嵌套函数中调用。
  3. 始终将状态下移到需要它的最低层组件——不必要地提升状态会导致过多重新渲染,并使无关组件产生耦合。
  4. 绝不直接在组件渲染过程中执行副作用——渲染后执行的副作用请使用 useEffect,异步获取数据请使用 Server Components。
  5. 始终让 Client Components 保持精简,并作为叶子节点——'use client' 组件中的代码越多,发送到浏览器的 JavaScript 就越多。

反模式

反模式为什么会失败正确做法
在新代码中使用类组件与 React Compiler、Server Components 和并发功能不兼容始终使用带 Hooks 的函数组件
有条件地或在循环中调用 Hooks违反 Hooks 规则;React 依赖各次渲染之间调用顺序的稳定性始终在顶层调用 Hooks;在 Hook 函数体内使用条件判断
到处手动使用 useMemo/useCallback过早优化;没有可衡量的收益,却增加了冗余和复杂度先进行性能分析;使用 React Compiler;只有 DevTools 显示确实存在重新渲染开销时才进行记忆化
在 useEffect 中获取数据会导致请求瀑布、加载闪烁和竞态条件异步获取数据请使用 Server Components;客户端缓存请使用 React Query
将大型组件标记为 'use client'会将整个组件树(包括服务器数据)打包到客户端 JavaScript 中将 'use client' 放在小型交互式叶子组件上;数据组件保持为 Server Components

记忆协议(强制)

开始之前:

cat .claude/context/memory/learnings.md

**完成之后:**记录发现的任何新模式或例外情况。

假设会被中断:你的上下文可能会重置。如果没有记录在记忆中,就等于没发生。

评论

支持 Markdown