programming-in-react

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Programming 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
interface
for props, avoid
React.FC
:
typescript
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:
React.MouseEvent<HTMLButtonElement>
,
React.ChangeEvent<HTMLInputElement>
. Children:
React.ReactNode
.
仅使用函数式组件。使用
interface
定义props,避免使用
React.FC
typescript
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.ReactNode

Workflow: 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 closures
useReducer 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:
  1. Local component state? � useState
  2. Multiple related state updates? � useReducer
  3. Shared across components? � Context API or custom hook
  4. 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用于复杂状态: 当状态包含多个关联的更新项,或下一个状态以复杂方式依赖前一个状态时使用。
状态管理决策框架:
  1. 局部组件状态? → 使用useState
  2. 多个关联状态更新? → 使用useReducer
  3. 跨组件共享状态? → 使用Context API或自定义hook
  4. 是否需要外部库? → 使用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
children: React.ReactNode
for wrapping components.
Custom 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: 提取可复用的有状态逻辑(优先于在组件中重复逻辑)。
复合组件: 用于实现
<Select><Select.Option /></Select>
这类复杂API。
渲染属性: 当组件控制渲染逻辑但父组件提供模板时使用。

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
useMemo
,
useCallback
,
React.memo
only when measurements show need. React 19 compiler handles most memoization automatically.
优化前先进行性能分析。仅当测量结果显示需要时,才使用
useMemo
useCallback
React.memo
。React 19编译器会自动处理大部分记忆化操作。

Common Rationalizations - STOP

常见错误认知——立即停止

ExcuseReality
"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

快速参考

TaskPattern
Props
interface Props {...}; function Comp({ prop }: Props)
State update
setState(prev => newValue)
when depends on current
Fetch on mount
useEffect(() => { fetch(...); return cleanup }, [])
Derived valueCalculate directly, NOT useEffect
List render
{items.map(item => <Item key={item.id} />)}
任务模式
Props定义
interface Props {...}; function Comp({ prop }: Props)
状态更新当依赖当前状态时,使用
setState(prev => newValue)
挂载时请求数据
useEffect(() => { fetch(...); return cleanup }, [])
派生值直接计算,不使用useEffect
列表渲染
{items.map(item => <Item key={item.id} />)}

Red Flags - STOP and Refactor

危险信号——立即停止并重构

  • React.FC
    in new code
  • useEffect
    with state as only dependency
  • Missing cleanup in useEffect
  • Array index as key:
    key={index}
  • Direct state mutation:
    state.value = x
  • Missing dependencies in useEffect (suppressing ESLint warning)
  • any
    type for props or event handlers
When you see these, refactor before proceeding.
  • 新代码中使用
    React.FC
  • useEffect仅依赖状态
  • useEffect中缺少清理操作
  • 使用数组索引作为key:
    key={index}
  • 直接修改状态:
    state.value = x
  • useEffect中遗漏依赖项(抑制ESLint警告)
  • props或事件处理程序使用
    any
    类型
当你遇到这些情况时,先重构再继续开发。