programming-in-react
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseProgramming in React
React编程
Overview
概述
Modern React development using functional components, hooks, and TypeScript. This skill guides you through React workflows from component creation to testing.
Core principle: Components are functions that return UI. State and effects are managed through hooks. Composition over inheritance always.
REQUIRED SUB-SKILL: Use ed3d-house-style:howto-code-in-typescript for general TypeScript patterns. This skill covers React-specific TypeScript usage only.
使用函数式组件、hooks和TypeScript进行现代React开发。本技能将指导你完成从组件创建到测试的React工作流。
核心原则: 组件是返回UI的函数。状态和副作用通过hooks管理。始终优先使用组合而非继承。
必备子技能: 通用TypeScript模式请使用ed3d-house-style:howto-code-in-typescript。本技能仅涵盖React特有的TypeScript用法。
When to Use
适用场景
- Creating or modifying React components
- Working with React hooks (useState, useEffect, custom hooks)
- Planning React features or UI work
- Debugging React-specific issues (hooks errors, render problems)
- When you see .jsx or .tsx files
- 创建或修改React组件
- 使用React hooks(useState、useEffect、自定义hooks)
- 规划React功能或UI工作
- 调试React相关问题(hooks错误、渲染问题)
- 处理.jsx或.tsx文件时
Workflow: Creating Components
工作流:创建组件
Functional components only. Use for props, avoid :
interfaceReact.FCtypescript
interface ButtonProps {
label: string;
onClick: () => void;
disabled?: boolean;
}
export function Button({ label, onClick, disabled }: ButtonProps) {
return <button onClick={onClick} disabled={disabled}>{label}</button>;
}Event typing: , . Children: .
React.MouseEvent<HTMLButtonElement>React.ChangeEvent<HTMLInputElement>React.ReactNode仅使用函数式组件。使用定义props,避免使用:
interfaceReact.FCtypescript
interface ButtonProps {
label: string;
onClick: () => void;
disabled?: boolean;
}
export function Button({ label, onClick, disabled }: ButtonProps) {
return <button onClick={onClick} disabled={disabled}>{label}</button>;
}事件类型: 、。子元素:。
React.MouseEvent<HTMLButtonElement>React.ChangeEvent<HTMLInputElement>React.ReactNodeWorkflow: Managing State
工作流:状态管理
useState for simple state:
typescript
const [count, setCount] = useState(0);
// Always use functional updates when new state depends on old
setCount(prev => prev + 1); // Good
setCount(count + 1); // Avoid - can be stale in closuresuseReducer for complex state:
When state has multiple related pieces that update together, or next state depends on previous state in complex ways.
State management decision framework:
- Local component state? � useState
- Multiple related state updates? � useReducer
- Shared across components? � Context API or custom hook
- Need external library? � Use codebase-investigator to find existing patterns, or internet-researcher to evaluate options (Zustand, Redux Toolkit, TanStack Query)
useState用于简单状态:
typescript
const [count, setCount] = useState(0);
// 当新状态依赖旧状态时,始终使用函数式更新
setCount(prev => prev + 1); // 推荐写法
setCount(count + 1); // 避免使用——闭包中可能出现状态过期问题useReducer用于复杂状态:
当状态包含多个关联的更新项,或下一个状态以复杂方式依赖前一个状态时使用。
状态管理决策框架:
- 局部组件状态? → 使用useState
- 多个关联状态更新? → 使用useReducer
- 跨组件共享状态? → 使用Context API或自定义hook
- 是否需要外部库? → 使用codebase-investigator查找现有模式,或通过internet-researcher评估可选方案(Zustand、Redux Toolkit、TanStack Query)
Workflow: Handling Side Effects
工作流:副作用处理
useEffect for external systems only (API calls, subscriptions, browser APIs). NOT for derived state.
Critical rules:
- Always include all dependencies (ESLint: react-hooks/exhaustive-deps)
- Always return cleanup function (prevents memory leaks)
- Think "which state does this sync with?" not "when does this run?"
Common pattern:
typescript
useEffect(() => {
const controller = new AbortController();
fetch('/api/data', { signal: controller.signal })
.then(res => res.json())
.then(data => setData(data));
return () => controller.abort(); // Cleanup
}, []);For comprehensive useEffect guidance (dependencies, cleanup, when NOT to use, debugging), see useEffect-deep-dive.md.
useEffect仅用于外部系统交互(API调用、订阅、浏览器API)。不可用于派生状态。
关键规则:
- 始终包含所有依赖项(ESLint规则:react-hooks/exhaustive-deps)
- 始终返回清理函数(防止内存泄漏)
- 思考“该副作用与哪些状态同步?”而非“该副作用何时执行?”
常见模式:
typescript
useEffect(() => {
const controller = new AbortController();
fetch('/api/data', { signal: controller.signal })
.then(res => res.json())
.then(data => setData(data));
return () => controller.abort(); // 清理操作
}, []);如需全面的useEffect指导(依赖项、清理操作、禁用场景、调试方法),请查看useEffect-deep-dive.md。
Workflow: Component Composition
工作流:组件组合
Children prop: Use for wrapping components.
children: React.ReactNodeCustom hooks: Extract reusable stateful logic (prefer over duplicating logic in components).
Compound components: For complex APIs like .
<Select><Select.Option /></Select>Render props: When component controls rendering but parent provides template.
Children属性: 使用实现组件包裹。
children: React.ReactNode自定义hooks: 提取可复用的有状态逻辑(优先于在组件中重复逻辑)。
复合组件: 用于实现这类复杂API。
<Select><Select.Option /></Select>渲染属性: 当组件控制渲染逻辑但父组件提供模板时使用。
Workflow: Testing
工作流:测试
ALWAYS use codebase-investigator first to find existing test patterns. Common approaches: React Testing Library, Playwright, Cypress.
See react-testing.md for comprehensive guidance.
始终先使用codebase-investigator查找现有测试模式。常见方案:React Testing Library、Playwright、Cypress。
如需全面指导,请查看react-testing.md。
Performance
性能优化
Profile before optimizing. Use , , only when measurements show need. React 19 compiler handles most memoization automatically.
useMemouseCallbackReact.memo优化前先进行性能分析。仅当测量结果显示需要时,才使用、、。React 19编译器会自动处理大部分记忆化操作。
useMemouseCallbackReact.memoCommon Rationalizations - STOP
常见错误认知——立即停止
| Excuse | Reality |
|---|---|
| "useEffect is fine for derived state" | Calculate derived values directly. useEffect for derived state causes extra renders and bugs. |
| "React.FC is the standard way" | Community moved away from React.FC. Use explicit function declarations with typed props. |
| "Cleanup doesn't matter for short operations" | Memory leaks are real. Always cleanup subscriptions, timers, and abort fetch requests. |
| "Missing dependencies is fine, I know what I'm doing" | Stale closures cause bugs. Always include all dependencies. Fix the root cause, don't lie to the linter. |
| "useCallback with all dependencies is correct" | Including state in deps creates new function every render AND stale closures. Use functional setState updates instead. |
| "This is Functional Core because it's pure logic" | Hooks with state are Imperative Shell or Mixed. Only pure functions without hooks are Functional Core. |
| "Array index as key is fine for static lists" | If list ever reorders, filters, or updates, you'll get bugs. Use stable unique IDs. |
| "Mutating state is faster" | React won't detect the change. Always create new objects/arrays. |
| 借口 | 实际情况 |
|---|---|
| "useEffect用于派生状态没问题" | 直接计算派生值即可。用useEffect处理派生状态会导致额外渲染和bug。 |
| "React.FC是标准写法" | 社区已逐渐摒弃React.FC。使用带类型props的显式函数声明。 |
| "短时间操作不需要清理" | 内存泄漏是真实存在的问题。始终清理订阅、定时器,并终止fetch请求。 |
| "遗漏依赖项没关系,我知道自己在做什么" | 过期闭包会引发bug。始终包含所有依赖项。修复根本问题,不要欺骗linter。 |
| "包含所有依赖项的useCallback是正确的" | 依赖项中包含状态会导致每次渲染创建新函数,同时引发过期闭包问题。改用函数式setState更新。 |
| "这是函数式核心,因为它是纯逻辑" | 带状态的hooks属于命令式外壳或混合模式。只有不含hooks的纯函数才是函数式核心。 |
| "静态列表用数组索引作为key没问题" | 一旦列表重新排序、过滤或更新,就会出现bug。使用稳定的唯一ID。 |
| "直接修改状态速度更快" | React无法检测到此类变更。始终创建新的对象/数组。 |
Quick Reference
快速参考
| Task | Pattern |
|---|---|
| Props | |
| State update | |
| Fetch on mount | |
| Derived value | Calculate directly, NOT useEffect |
| List render | |
| 任务 | 模式 |
|---|---|
| Props定义 | |
| 状态更新 | 当依赖当前状态时,使用 |
| 挂载时请求数据 | |
| 派生值 | 直接计算,不使用useEffect |
| 列表渲染 | |
Red Flags - STOP and Refactor
危险信号——立即停止并重构
- in new code
React.FC - with state as only dependency
useEffect - Missing cleanup in useEffect
- Array index as key:
key={index} - Direct state mutation:
state.value = x - Missing dependencies in useEffect (suppressing ESLint warning)
- type for props or event handlers
any
When you see these, refactor before proceeding.
- 新代码中使用
React.FC - useEffect仅依赖状态
- useEffect中缺少清理操作
- 使用数组索引作为key:
key={index} - 直接修改状态:
state.value = x - useEffect中遗漏依赖项(抑制ESLint警告)
- props或事件处理程序使用类型
any
当你遇到这些情况时,先重构再继续开发。