mcpField
R
react

react

github.com/claude-dev-suite开发4643 次安装4 天前更新
代码仓库

关于 react

react 是面向 React 应用开发者的参考技能,涵盖组件与 Hooks 模式、性能、无障碍、安全、测试和故障排查。

主要功能

  1. 01函数组件与 Props 模式
  2. 02常用 React Hooks
  3. 03状态与组合指导
  4. 04性能优化
  5. 05无障碍与安全实践
  6. 06测试与故障排查指导

适用场景

  1. 01组织可复用的 React 组件
  2. 02管理本地与共享状态
  3. 03诊断 Hooks 和渲染问题
  4. 04检查无障碍与生产就绪情况

MCP 相关

README 指向 mcp__documentation__fetch_docs,并使用 technology `react` 获取完整的 React 文档。

安装

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

$npx skills add https://github.com/claude-dev-suite/claude-dev-suite --skill react

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

附带文件quick-ref/component-patterns.mdquick-ref/hooks-cheatsheet.md

详细介绍

React Core 知识

深入了解:使用 mcp__documentation__fetch_docs 并指定技术:react,获取有关 hooks、组件和 React 模式的全面文档。

组件模式

函数组件(首选)
function UserCard({ name, email }: UserCardProps) {
  return (
    <div className="card">
      <h2>{name}</h2>
      <p>{email}</p>
    </div>
  );
}
Props 类型
interface Props {
  title: string;
  count?: number;
  children: React.ReactNode;
  onClick: (id: string) => void;
}

必备 Hooks

Hook用途
useState本地状态
useEffect副作用、订阅
useContext访问上下文值
useRefDOM 引用、可变值
useMemo缓存开销较大的计算
useCallback缓存函数
useReducer复杂状态逻辑

关键模式

  • 组合优于继承
  • 共享状态时向上提升状态
  • Props 层层传递 → 使用 Context 或状态库
  • 受控与非受控输入

性能

  • 对开销较大的纯组件使用 React.memo()
  • 仅在需要时使用 useMemo/useCallback 进行缓存
  • 在列表中正确使用 key 属性
  • 使用 React.lazy() + Suspense 延迟加载

生产就绪

安全最佳实践
// NEVER use dangerouslySetInnerHTML with user input
// BAD
<div dangerouslySetInnerHTML={{ __html: userInput }} />

// GOOD - Sanitize with DOMPurify
import DOMPurify from 'dompurify';
<div dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(userInput) }} />

// Avoid exposing sensitive data in client-side state
// BAD
const [apiKey, setApiKey] = useState(process.env.API_KEY);

// GOOD - API keys should stay server-side
// Use API routes or server actions instead

// Validate all external URLs
const isValidUrl = (url: string) => {
  try {
    const parsed = new URL(url);
    return ['http:', 'https:'].includes(parsed.protocol);
  } catch {
    return false;
  }
};
错误边界
import { ErrorBoundary } from 'react-error-boundary';

function ErrorFallback({ error, resetErrorBoundary }: FallbackProps) {
  return (
    <div role="alert">
      <p>Something went wrong:</p>
      <pre>{error.message}</pre>
      <button onClick={resetErrorBoundary}>Try again</button>
    </div>
  );
}

// Usage
<ErrorBoundary
  FallbackComponent={ErrorFallback}
  onReset={() => window.location.reload()}
  onError={(error, info) => {
    // Log to error reporting service
    logErrorToService(error, info);
  }}
>
  <App />
</ErrorBoundary>
性能优化
// Code splitting with lazy loading
const Dashboard = lazy(() => import('./Dashboard'));

function App() {
  return (
    <Suspense fallback={<Skeleton />}>
      <Dashboard />
    </Suspense>
  );
}

// Memoization - use sparingly, only for expensive components
const ExpensiveList = memo(function ExpensiveList({ items }: Props) {
  return items.map(item => <ExpensiveItem key={item.id} {...item} />);
});

// Virtualization for large lists
import { FixedSizeList } from 'react-window';

function VirtualList({ items }: { items: Item[] }) {
  return (
    <FixedSizeList
      height={400}
      itemCount={items.length}
      itemSize={50}
      width="100%"
    >
      {({ index, style }) => (
        <div style={style}>{items[index].name}</div>
      )}
    </FixedSizeList>
  );
}
无障碍(a11y)
// Use semantic HTML
<button onClick={handleClick}>Submit</button>  // NOT <div onClick>

// ARIA labels for icons/images
<button aria-label="Close dialog" onClick={onClose}>
  <XIcon />
</button>

// Focus management
const dialogRef = useRef<HTMLDivElement>(null);
useEffect(() => {
  dialogRef.current?.focus();
}, [isOpen]);

// Keyboard navigation
const handleKeyDown = (e: KeyboardEvent) => {
  if (e.key === 'Escape') onClose();
  if (e.key === 'Tab') trapFocus(e);
};
测试配置
// Component testing with Testing Library
import { render, screen, userEvent } from '@testing-library/react';

test('submits form with user data', async () => {
  const onSubmit = vi.fn();
  render(<Form onSubmit={onSubmit} />);

  await userEvent.type(screen.getByLabelText(/email/i), '[email protected]');
  await userEvent.click(screen.getByRole('button', { name: /submit/i }));

  expect(onSubmit).toHaveBeenCalledWith({ email: '[email protected]' });
});
监控指标
指标告警阈值
最大内容绘制(LCP)> 2.5s
首次输入延迟(FID)> 100ms
累积布局偏移(CLS)> 0.1
JavaScript 包大小> 200KB(gzip 压缩后)
组件渲染时间> 16ms
构建与包优化
// vite.config.ts
export default defineConfig({
  build: {
    rollupOptions: {
      output: {
        manualChunks: {
          vendor: ['react', 'react-dom'],
          ui: ['@radix-ui/react-dialog', '@radix-ui/react-dropdown'],
        },
      },
    },
    sourcemap: true,  // For error tracking in production
  },
});
检查清单
  • 为关键区域添加错误边界
  • 客户端状态中不包含敏感数据
  • 渲染任何 HTML 时使用 DOMPurify
  • 为基于路由的代码拆分启用延迟加载
  • 对大型列表(>100 项)使用虚拟化
  • 使用语义化 HTML 和 ARIA 标签
  • 支持键盘导航
  • 监控 Core Web Vitals
  • 优化包大小(<200KB gzip)
  • 提供用于生产环境调试的源映射
  • 集成错误报告服务

不应使用此技能的情况

  • React 19 专属功能(Actions、useActionState、use())——改用 react-19 技能
  • 高级性能优化——改用 react-performance 技能
  • 表单处理模式——改用 react-forms 或 react-hook-form 技能
  • 路由——改用 react-router 技能
  • 测试——改用 react-testing 技能
  • 组件设计模式——改用 react-patterns 技能

反模式

反模式问题解决方案
直接修改状态不会触发重新渲染使用 setState 并传入新的对象/数组
缺少依赖数组闭包过期、内存泄漏包含所有依赖项或使用 ESLint
使用 useEffect 派生状态额外的重新渲染在渲染期间计算或使用 useMemo
Props 深层层层传递难以维护使用 Context 或状态库
在 JSX 中内联对象/数组会破坏缓存提取为常量或使用 useMemo
在渲染期间创建新函数导致子组件不必要地重新渲染使用 useCallback
忘记在 useEffect 中清理内存泄漏返回清理函数
使用索引作为 key重新渲染不正确使用稳定的唯一 ID

快速故障排查

问题可能原因修复方法
组件未重新渲染状态被修改使用 setState 并传入新的引用
useEffect 中出现无限循环缺少/错误的依赖项添加依赖项或使用函数式更新
“Cannot read property of undefined”异步数据尚未加载添加空值检查或加载状态
内存泄漏警告缺少清理从 useEffect 返回清理函数
子组件未更新使用索引作为 key使用稳定的唯一 ID
处理函数未触发事件传播已停止检查 stopPropagation() 调用
回调中的状态过期闭包引用了旧状态使用函数式 setState

Reference Documentation

评论

支持 Markdown