Local MCP Server
在Termux中运行本地MCP服务器,支持Ollama模型的文件读取与命令执行。
涵盖 React 19 全栈开发规范,含架构、状态管理与性能优化最佳实践。
openclaw skills install @ivangdavila/react命令、参数、文件名以原文为准
生产级别的 React 工程实践。此技能将改变你构建 React 应用的方式——从组件架构到部署全流程。
在编写代码前,请先做出以下决定:
| 决策 | 可选项 | 默认值 |
|---|---|---|
| 渲染方式 | SPA / SSR / 静态 / 混合 | SSR(Next.js) |
| 服务端状态 | TanStack Query / SWR / use() | TanStack Query |
| 客户端状态 | useState / Zustand / Jotai | Zustand(若需共享) |
| 样式方案 | Tailwind / CSS Modules / styled | Tailwind |
| 表单处理 | React Hook Form + Zod / 原生表单 | RHF + Zod |
规则: 服务端状态(API 数据)与客户端状态(UI 状态)必须分离。绝不混合使用。
// ✅ 正确的编写模式
export function UserCard({ user, onEdit }: UserCardProps) {
// 1. 钩子优先(始终如此)
const [isOpen, setIsOpen] = useState(false)
// 2. 派生状态(不通过 useEffect 实现)
const fullName = `${user.firstName} ${user.lastName}`
// 3. 事件处理器
const handleEdit = useCallback(() => onEdit(user.id), [onEdit, user.id])
// 4. 提前返回
if (!user) return null
// 5. JSX(不超过 50 行)
return (...)
}| 规则 | 原因 |
|---|---|
| 仅使用命名导出 | 支持重构安全性和 IDE 支持 |
| 导出 Props 接口 | 可复用、可文档化 |
| JSX 最多 50 行 | 超过则提取为独立组件 |
| 单个文件最多 300 行 | 超过则拆分为多个组件 |
| 钩子置于顶部 | 符合 React 规范,逻辑更清晰 |
是否来自 API?
├─ 是 → TanStack Query(非 Redux,非 Zustand)
└─ 否 → 是否在多个组件间共享?
├─ 是 → Zustand(简单场景)或 Context(更新频率低)
└─ 否 → useState// 查询键工厂 — 防止键名拼写错误
export const userKeys = {
all: ['users'] as const,
detail: (id: string) => [...userKeys.all, id] as const,
}
export function useUser(id: string) {
return useQuery({
queryKey: userKeys.detail(id),
queryFn: () => fetchUser(id),
staleTime: 5 * 60 * 1000, // 5 分钟
})
}// 简洁的状态存储,单一职责
export const useUIStore = create<UIState>()((set) => ({
sidebarOpen: true,
toggleSidebar: () => set((s) => ({ sidebarOpen: !s.sidebarOpen })),
}))
// 始终使用选择器 — 避免不必要的重新渲染
const isOpen = useUIStore((s) => s.sidebarOpen)// 服务器组件 — 在服务端运行,不会发送任何 JS 到客户端
async function ProductList() {
const products = await db.products.findMany() // 直接访问数据库
return <ul>{products.map(p => <ProductCard key={p.id} product={p} />)}</ul>
}
// 客户端组件 — 必须添加 'use client' 指令
'use client'
function AddToCartButton({ productId }: { productId: string }) {
const [loading, setLoading] = useState(false)
return <button onClick={() => addToCart(productId)}>添加</button>
}| 服务器组件 | 客户端组件 |
|---|---|
| 支持 async/await ✅ | 支持 useState ✅ |
| 支持直接数据库访问 ✅ | 支持 onClick ✅ |
| 不增加打包体积 | 会增加打包体积 |
| 不支持 useState ❌ | 不支持 async ❌ |
// 在渲染中读取 Promise(配合 Suspense 使用)
function Comments({ promise }: { promise: Promise<Comment[]> }) {
const comments = use(promise) // 渲染时暂停,直到解析完成
return <ul>{comments.map(c => <li key={c.id}>{c.text}</li>)}</ul>
}'use client'
async function submitAction(prev: State, formData: FormData) {
'use server'
// ... 服务端逻辑
return { success: true }
}
function Form() {
const [state, action, pending] = useActionState(submitAction, {})
return (
<form action={action}>
<input name="email" disabled={pending} />
<button disabled={pending}>{pending ? '保存中...' : '保存'}</button>
{state.error && <p>{state.error}</p>}
</form>
)
}| 优先级 | 技术 | 影响程度 |
|---|---|---|
| P0 | 路由级代码分割 | 🔴 高 |
| P0 | 图片优化(next/image) | 🔴 高 |
| P1 | 长列表虚拟化(tanstack-virtual) | 🟡 中等 |
| P1 | 消除昂贵操作的频繁触发(防抖) | 🟡 中等 |
| P2 | 对计算密集型组件使用 React.memo | 🟢 低至中等 |
| P2 | 对复杂计算使用 useMemo | 🟢 低至中等 |
React Compiler(React 19+): 自动进行记忆化处理。移除手动的 memo/useMemo/useCallback。
// ❌ 当 count 为 0 时会渲染 "0"
{count && <Component />}
// ✅ 明确判断布尔值
{count > 0 && <Component />}// ❌ 修改状态 — React 无法检测到变化
array.push(item)
setArray(array)
// ✅ 创建新引用
setArray([...array, item])// ❌ 每次渲染都生成新 key — 导致组件被销毁重建
<Item key={Math.random()} />
// ✅ 使用稳定 key
<Item key={item.id} />// ❌ useEffect 不能是 async 函数
useEffect(async () => { ... }, [])
// ✅ 在内部定义异步函数
useEffect(() => {
async function load() { ... }
load()
}, [])// ❌ 缺少清理函数 — 内存泄漏
useEffect(() => {
const sub = subscribe()
}, [])
// ✅ 返回清理函数
useEffect(() => {
const sub = subscribe()
return () => sub.unsubscribe()
}, [])// ❌ 依赖项中包含对象 — 每次渲染都会触发
useEffect(() => { ... }, [{ id: 1 }])
// ✅ 提取基础类型或使用 memoize
useEffect(() => { ... }, [id])// ❌ 串行请求 — 效率低下
const users = await fetchUsers()
const orders = await fetchOrders()
// ✅ 并行请求
const [users, orders] = await Promise.all([fetchUsers(), fetchOrders()])tsx
// ❌ 竞态条件 — 无法中止请求
useEffect(() => {
fetch(url).then(setData)
}, [url])
// ✅ 使用 AbortController 中止请求
useEffect(() => {
const controller = new AbortController()
fetch(url, { signal: controller.signal }).then(setData)
return () => controller.abort()
}, [url])
## AI 常见错误避免
AI 助手在使用 React 时常见的错误:
| 错误 | 正确模式 |
|------|----------|
| 使用 useEffect 处理派生状态 | 直接计算:`const x = a + b` |
| 使用 Redux 管理 API 数据 | 使用 TanStack Query 管理服务器状态 |
| 使用默认导出 | 使用命名导出:`export function X` |
| 动态列表中使用索引作为 key | 使用稳定 ID:`key={item.id}` |
| 在 useEffect 中发起请求 | 使用 TanStack Query 或 loader 模式 |
| 单个组件过大(超过 500 行) | JSX 超过 50 行即拆分,文件不超过 300 行 |
| 忽略错误边界 | 在应用、功能或组件层级添加错误边界 |
| 忽视 TypeScript 严格模式 | 启用 strict: true,修复所有错误 |
## 快速参考
### Hooks
| Hook | 用途 |
|------|------|
| useState | 本地状态管理 |
| useEffect | 处理副作用(如订阅、DOM 操作) |
| useCallback | 保持函数引用稳定 |
| useMemo | 处理开销较大的计算 |
| useRef | 可变引用,用于访问 DOM |
| use() | 读取 Promise 或上下文(React 19) |
| useActionState | 表单动作状态(React 19) |
| useOptimistic | 实现乐观 UI(React 19) |
### 文件结构src/
├── app/ # 路由(Next.js)
├── features/ # 功能模块
│ └── auth/
│ ├── components/ # 功能组件
│ ├── hooks/ # 功能 Hook
│ ├── api/ # API 调用
│ └── index.ts # 公共导出
├── shared/ # 跨功能共享
│ ├── components/ui/ # Button、Input 等通用组件
│ └── hooks/ # useDebounce 等工具 Hook
└── providers/ # 上下文提供者
## 设置
请参阅 `setup.md` 获取首次配置说明。项目跟踪使用 `memory-template.md`。
## 核心规则
1. **服务器状态 ≠ 客户端状态** — API 数据使用 TanStack Query 管理,UI 状态使用 useState/Zustand。禁止混合。
2. **仅使用命名导出** — 使用 `export function X`,而非 `export default`。支持安全重构。
3. **先聚合,再提取** — 初始将状态放在使用位置附近。仅在需要时提升。
4. **不要用 useEffect 处理派生状态** — 直接计算:`const total = items.reduce(...)`。Effects 仅用于副作用。
5. **始终使用稳定 key** — 使用 `item.id`,不要使用 `index` 作为动态列表的 key。
6. **JSX 最多 50 行** — 超过则拆分为独立组件。单个文件最多 300 行。
7. **启用 TypeScript strict: true** — 禁止使用 `any`,禁止隐式空值。在编译期捕获错误。
## 相关技能
通过 `clawhub install <slug>` 安装(用户确认后):
- **frontend-design-ultimate** — 使用 React + Tailwind 构建完整 UI
- **typescript** — TypeScript 使用模式与严格配置
- **nextjs** — Next.js App Router 与部署
- **testing** — 使用 Testing Library 测试 React 组件
## 反馈
- 若有帮助:`clawhub star react`
- 保持更新:`clawhub sync`已收录 16 个 Skill