Local MCP Server
在Termux中运行本地MCP服务器,支持Ollama模型的文件读取与命令执行。
提供 React、TypeScript、Next.js 等技术的架构与编码规范,涵盖状态管理、性能优化与测试实践。
openclaw skills install @iliaal/compound-eng-react-frontend命令、参数、文件名以原文为准
实施前验证:对于 App Router 模式、React 19 API 或版本特定行为,请通过 Context7 (query-docs) 查阅最新文档,再编写代码。训练数据可能滞后于最新发布版本。
ComponentPropsWithoutRef<'button'> 扩展原生元素,通过交叉类型添加自定义属性React.ReactNode,单个元素使用 React.ReactElement,渲染函数使用 (data: T) => ReactNode<T> 配合 keyof T 表示列键,T extends { id: string } 添加约束React.MouseEvent<HTMLButtonElement>,FormEvent<HTMLFormElement>,ChangeEvent<HTMLInputElement>as const 标记自定义 Hook 的元组返回值useRef<HTMLInputElement>(null)(配合 ?.),可变值使用 useRef<number>(0)useState<User | null>(null) 处理联合类型或空值{ type: 'set'; payload: number } | { type: 'reset' }useX() Hook 中,若上下文为 null 则抛出异常Effects 是逃生通道 —— 大多数逻辑不应使用 Effects。
| 需求 | 解决方案 |
|---|---|
| 从 props 或 state 派生的值 | 在渲染期间计算(如开销大,使用 useMemo) |
| prop 变化时重置状态 | 使用组件的 key 属性 |
| 响应用户事件 | 事件处理器 |
| 通知父组件状态变化 | 在事件处理器中调用 onChange,或使用完全受控组件 |
| 状态更新链 | 在一个事件处理器中一次性计算所有下一状态 |
| 与外部系统同步 | 使用带清理函数的 Effect |
Effect 规则:
setItems(prev => [...prev, item]))以消除状态依赖useEffectEvent(例如连接中的主题)AbortController 用于 fetch;ignore 标志用于不可取消的 Promise;React Query 自动处理两者前端 bug 在通过类型检查和单元测试后,通常属于以下五类竞态。审查时需明确排查:
useEffect 注册了监听器/定时器/观察者但未返回清理函数(参见 Effect 规则)。fetch().then(setData) 在导航到不同路由后才完成;requestAnimationFrame 在父组件卸载后仍触发。参见 Effect 规则中的“数据获取”部分关于取消层级。isLoading: boolean 无法表达 idle | loading | success | error | retry,否则会产生不一致组合(如 isLoading: true, error: Error 相互矛盾)。建议使用显式状态常量('idle' | 'loading' | 'success' | 'error')并配合转换函数,使无效状态不可达。setTimeout 保留对 setState 的引用,而组件已离开。每个异步操作都必须绑定到取消机制(参见上述取消层级),并通过测试验证清理路径被正确执行。onClick 会创建 N 个闭包和 N 个订阅;使用单一父级处理器,通过 event.target.closest(...) 读取目标,更安全,避免在频繁重渲染下出现闭包过期问题,并支持大规模列表。当列表超过约 50 项或频繁更新时,应优先使用事件委托。这些类别产生的 bug 具有间歇性、环境依赖性和类型检查无法发现的特点 —— 正是那些进入生产环境的问题。必须主动审查,而非仅关注“订阅需要清理”。
本地 UI 状态 → useState, useReducer
共享客户端状态 → Zustand (简单) | Redux Toolkit (复杂)
原子化/细粒度 → Jotai
服务器/远程数据 → React Query (TanStack Query)
URL 状态 → nuqs, router search params
表单状态 → React Hook Form关键模式:
create<State>()(devtools(persist((set) => ({...})))) —— 使用切片提升可扩展性,选择性订阅防止不必要的重渲染['users', 'detail', id] as const),staleTime/gcTime,通过 onMutate/onError 实现乐观更新与回滚关键 —— 消除瀑布流:
Promise.all()await 移至实际需要的位置关键 —— 包体积优化:
index.ts 重新导出)next/dynamic 或 React.lazy()content-visibility: auto + contain-intrinsic-size —— 跳过屏幕外的布局/绘制重新渲染优化:
state.items.length > 0 而非 state.items)setCount(c => c + 1)useState(() => expensiveComputation())useTransition(如搜索过滤)useDeferredValuesearchParams/state,则不要订阅——改为按需读取condition ? <A /> : <B />),而非 && 实现条件渲染React.memo 仅用于具有稳定 props 的昂贵子树React Compiler(React 19):自动记忆化——编写符合惯例的 React 代码,移除手动的 useMemo/useCallback/memo。通过框架配置启用(Next.js:在 next.config 中设置 reactCompiler: true)。非框架项目:安装 babel-plugin-react-compiler。保持组件纯净。
forwardRef 已弃用。将 ref?: React.Ref<HTMLElement> 作为普通 prop 接收useFormState:const [state, formAction, isPending] = useActionState(action, initialState)const [optimistic, addOptimistic] = useOptimistic(state, mergeFn),用于即时 UI 反馈<form action={...}> 的子组件中使用:const { pending } = useFormStatus()'use server' 指令。验证输入(如 Zod),在变更后调用 revalidateTag/revalidatePath。服务器动作是公开端点——每个动作内部都必须验证身份认证和权限,不能仅依赖中间件或布局守卫<Activity mode='visible'|'hidden'>** —— 保留切换组件的状态和 DOM(实验性)文件命名规范:
page.tsx(路由界面)
layout.tsx(共享包装器)
template.tsx(导航时重新挂载,不同于 layout)
loading.tsx(Suspense)
error.tsx(错误边界)
not-found.tsx(404 页面)
default.tsx(并行路由的回退)
route.ts(API 端点)
渲染模式:
服务器组件(默认) | 客户端('use client') | 静态(构建时) | 动态(请求时) | 流式(渐进式)
决策原则:
除非需要 hooks、事件处理器或浏览器 API,否则使用服务器组件。拆分结构:服务器父组件 + 客户端子组件。将交互式组件作为 'use client' 的叶子组件隔离——保持服务器组件静态,无全局状态或事件处理器。
路由模式:
(name) —— 用于组织,不影响 URL@slot —— 同一布局中独立的加载状态(.) —— 模态覆盖层,带完整页面回退缓存策略:
fetch(url, { cache: 'force-cache' }) —— 静态缓存fetch(url, { next: { revalidate: 60 } }) —— ISR(增量静态再生)fetch(url, { cache: 'no-store' }) —— 动态请求fetch(url, { next: { tags: ['products'] } }),随后调用 revalidateTag('products')数据获取:
在使用数据的服务器组件中进行 fetch。对慢查询使用 Suspense 边界。使用 React.cache() 实现每请求去重。使用 generateStaticParams 进行静态生成。使用 generateMetadata 实现动态 SEO。静态元数据使用 title: { default: 'App', template: '%s | App' } 实现页面标题级联。使用 after() 执行非阻塞副作用(如日志、分析)——在响应发送后运行。将静态 I/O(字体、配置)提升至模块级别——仅执行一次,而非每次请求都执行。
*.test.tsx 文件。适用于 React 组件的默认测试方式renderHook + act,同目录的 *.test.ts 文件getByRole > getByLabelText > getByPlaceholderText > getByText > getByTestIdshould <行为> when <条件>userEvent 而非 fireEvent,以模拟真实交互findBy*,在状态触发动作后使用 waitForbeforeEach 中调用 vi.clearAllMocks()。每次测试重建状态参考 [testing patterns and examples](./references/testing.md) 获取组件、钩子和模拟示例
参考 [e2e testing](./references/e2e-testing.md) 获取 Playwright 测试模式
关于 Tailwind v4 的配置、实用类模式、暗色模式、组件变体等内容,请参见 [ia-tailwind-css](../tailwind-css/SKILL.md) 技能文档。
JSX 中的类名排序:当使用 clsx、cva、cn、tv 或 tw 等工具函数时,保持 Tailwind 类名按标准顺序排列。通过配置 eslint-plugin-better-tailwindcss 插件,启用 useSortedClasses 并设置 functions: ["clsx", "cva", "cn", "tv", "tw"],可自动强制在 JSX 属性和辅助函数调用中保持类名有序。
eslint-disable、@ts-ignore)useEffect 依赖项数组不手动覆盖forwardRef(直接使用 ref 属性)已收录 1 个 Skill