react-development
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseReact Development
React开发
Modern React patterns from the official docs and community expertise.
来自官方文档和社区经验的现代React模式。
Instructions
操作指南
When working with React code, apply these principles in order of importance:
在处理React代码时,请按照以下优先级应用这些原则:
1. Think in React
1. 以React思维思考
Follow the 5-step process for building React UIs:
- Break UI into component hierarchy — One component = one responsibility
- Build static version first — Use props only, no state yet
- Find minimal state — Ask: Does it change? Is it passed via props? Can it be computed?
- Identify where state lives — Find closest common parent of components that need it
- Add inverse data flow — Pass callbacks down to update parent state
遵循构建React UI的5步流程:
- 将UI拆分为组件层级 — 一个组件对应一项职责
- 先构建静态版本 — 仅使用props,暂不使用state
- 找出最小化状态 — 自问:它会变化吗?是通过props传递的吗?能否通过计算得到?
- 确定状态的存放位置 — 找到需要该状态的组件的最近共同父组件
- 添加反向数据流 — 向下传递回调函数以更新父组件状态
2. Keep Components Pure
2. 保持组件纯净
Components must be pure functions during rendering:
jsx
// ❌ Mutates external variable
let guest = 0;
function Cup() {
guest = guest + 1;
return <h2>Guest #{guest}</h2>;
}
// ✅ Uses props
function Cup({ guest }) {
return <h2>Guest #{guest}</h2>;
}Rules:
- Never mutate props, state, or context during render
- Same inputs = same output
- Side effects belong in event handlers or useEffect
组件在渲染期间必须是纯函数:
jsx
// ❌ 修改外部变量
let guest = 0;
function Cup() {
guest = guest + 1;
return <h2>Guest #{guest}</h2>;
}
// ✅ 使用props
function Cup({ guest }) {
return <h2>Guest #{guest}</h2>;
}规则:
- 渲染期间绝不要修改props、state或context
- 相同输入必须得到相同输出
- 副作用应放在事件处理器或useEffect中
3. State Management
3. 状态管理
Minimize state:
jsx
// ❌ Redundant state
const [firstName, setFirstName] = useState('');
const [lastName, setLastName] = useState('');
const [fullName, setFullName] = useState(''); // redundant!
// ✅ Compute during render
const [firstName, setFirstName] = useState('');
const [lastName, setLastName] = useState('');
const fullName = firstName + ' ' + lastName;Lift state up when siblings need the same data — move to closest common parent.
Use key to reset state:
jsx
// Forces fresh component instance when recipient changes
<Chat key={recipientId} contact={recipient} />最小化状态:
jsx
// ❌ 冗余状态
const [firstName, setFirstName] = useState('');
const [lastName, setLastName] = useState('');
const [fullName, setFullName] = useState(''); // 冗余!
// ✅ 在渲染时计算
const [firstName, setFirstName] = useState('');
const [lastName, setLastName] = useState('');
const fullName = firstName + ' ' + lastName;当兄弟组件需要相同数据时提升状态 — 将状态移至最近的共同父组件。
使用key重置状态:
jsx
// 当recipient变化时强制创建新的组件实例
<Chat key={recipientId} contact={recipient} />4. Hooks Rules
4. Hooks规则
Only call hooks at the top level:
- Never in loops, conditions, or nested functions
- Never after early returns
- React relies on consistent call order
Only call hooks from React functions:
- Function components or custom hooks only
仅在顶层调用Hooks:
- 绝不要在循环、条件判断或嵌套函数中调用
- 绝不要在提前return之后调用
- React依赖于稳定的调用顺序
仅在React函数中调用Hooks:
- 只能在函数组件或自定义Hooks中调用
5. Effects — Use Sparingly
5. Effects — 谨慎使用
Effects are for synchronizing with external systems, not for state logic.
You DON'T need useEffect for:
| Scenario | Instead of Effect | Do This |
|---|---|---|
| Transform data for render | | Calculate during render |
| Cache expensive calculations | | |
| Reset state on prop change | | Use |
| Handle user events | | Event handler directly |
| Notify parent of changes | | Call in event handler |
When you DO need useEffect:
- Fetching data (with cleanup for race conditions)
- Subscribing to events (with cleanup to unsubscribe)
- Controlling non-React widgets
- Connecting to external systems
Always add cleanup:
jsx
useEffect(() => {
const connection = createConnection();
connection.connect();
return () => connection.disconnect(); // cleanup
}, []);Effects用于与外部系统同步,而非处理状态逻辑。
不需要使用useEffect的场景:
| 场景 | 替代useEffect的方案 | 具体操作 |
|---|---|---|
| 转换渲染用的数据 | | 在渲染时计算 |
| 缓存昂贵的计算结果 | | 使用 |
| 当props变化时重置状态 | | 使用 |
| 处理用户事件 | 监听state的useEffect | 直接使用事件处理器 |
| 通知父组件状态变化 | 调用回调的useEffect | 在事件处理器中调用 |
需要使用useEffect的场景:
- 获取数据(需清理以避免竞态条件)
- 订阅事件(需清理以取消订阅)
- 控制非React组件
- 连接外部系统
始终添加清理逻辑:
jsx
useEffect(() => {
const connection = createConnection();
connection.connect();
return () => connection.disconnect(); // 清理逻辑
}, []);6. Performance
6. 性能优化
Before reaching for memo:
- Move state down — Isolate state to components that use it
- Lift content up — Pass expensive subtrees as
children
Virtualize large lists (50+ items):
jsx
import { FixedSizeList } from 'react-window';
<FixedSizeList height={400} itemCount={1000} itemSize={35}>
{({ index, style }) => <div style={style}>{items[index]}</div>}
</FixedSizeList>Code split routes:
jsx
const Dashboard = lazy(() => import('./Dashboard'));
<Suspense fallback={<Loading />}>
<Dashboard />
</Suspense>在使用memo之前,请先尝试:
- 将状态下移 — 将状态隔离到需要它的组件中
- 将内容上移 — 将开销较大的子树作为传递
children
虚拟化大型列表(50项以上):
jsx
import { FixedSizeList } from 'react-window';
<FixedSizeList height={400} itemCount={1000} itemSize={35}>
{({ index, style }) => <div style={style}>{items[index]}</div>}
</FixedSizeList>路由代码分割:
jsx
const Dashboard = lazy(() => import('./Dashboard'));
<Suspense fallback={<Loading />}>
<Dashboard />
</Suspense>7. Component Design Principles
7. 组件设计原则
From "Writing Resilient Components":
- Don't stop the data flow — Read props directly, don't copy to state
- Always be ready to render — Don't assume render timing or frequency
- No component is a singleton — Design as if rendered multiple times
- Keep local state isolated — Only local if it wouldn't sync across copies
来自《编写高韧性组件》:
- 不要中断数据流 — 直接读取props,不要复制到state中
- 随时准备好渲染 — 不要假设渲染的时机或频率
- 没有组件是单例 — 按照可多次渲染的方式设计
- 保持局部状态隔离 — 仅当状态无需在多个副本间同步时才作为局部状态
8. Context — Use Judiciously
8. Context — 审慎使用
Good for: theming, current user, routing, widely-needed state.
Try these first:
- Pass props explicitly — clearer data flow
- Extract components and use — avoids prop drilling
children
jsx
// ❌ Prop drilling
<Layout posts={posts} />
// ✅ Composition
<Layout>
<Posts posts={posts} />
</Layout>适用场景:主题设置、当前用户、路由、广泛需要的状态。
请先尝试以下方案:
- 显式传递props — 数据流更清晰
- 提取组件并使用— 避免props透传
children
jsx
// ❌ Props透传
<Layout posts={posts} />
// ✅ 组合方式
<Layout>
<Posts posts={posts} />
</Layout>Common Anti-Patterns
常见反模式
| Anti-Pattern | Problem | Fix |
|---|---|---|
| Copying props to state | Stale data | Read props directly |
| Effect chains | Cascading renders | Compute in event handlers |
| Suppressing effect with refs | Hides bugs | Add proper cleanup |
| Derived state in useState | Sync issues | Compute during render |
| Missing keys in lists | Broken updates | Use stable unique IDs |
| Index as key (for reorderable lists) | State mismatch | Use item IDs |
| 反模式 | 问题 | 修复方案 |
|---|---|---|
| 将props复制到state中 | 数据过期 | 直接读取props |
| Effect链式调用 | 级联渲染 | 在事件处理器中计算 |
| 使用refs抑制Effect | 隐藏bug | 添加正确的清理逻辑 |
| 在useState中使用派生状态 | 同步问题 | 在渲染时计算 |
| 列表中缺少key | 更新异常 | 使用稳定的唯一ID |
| (可重排序列表中)使用索引作为key | 状态不匹配 | 使用项的ID |
Examples
示例
Well-Structured Component
结构良好的组件
jsx
function ProductList({ products, onSelect }) {
// Derived state — computed, not stored
const sortedProducts = useMemo(
() => [...products].sort((a, b) => a.name.localeCompare(b.name)),
[products]
);
// Event handler — not useEffect
function handleClick(product) {
onSelect(product);
}
return (
<ul>
{sortedProducts.map(product => (
<li key={product.id} onClick={() => handleClick(product)}>
{product.name}
</li>
))}
</ul>
);
}jsx
function ProductList({ products, onSelect }) {
// 派生状态 — 计算得到,而非存储
const sortedProducts = useMemo(
() => [...products].sort((a, b) => a.name.localeCompare(b.name)),
[products]
);
// 事件处理器 — 而非useEffect
function handleClick(product) {
onSelect(product);
}
return (
<ul>
{sortedProducts.map(product => (
<li key={product.id} onClick={() => handleClick(product)}>
{product.name}
</li>
))}
</ul>
);
}Data Fetching with Cleanup
带清理逻辑的数据获取
jsx
function UserProfile({ userId }) {
const [user, setUser] = useState(null);
useEffect(() => {
let cancelled = false;
async function fetchUser() {
const data = await getUser(userId);
if (!cancelled) setUser(data);
}
fetchUser();
return () => { cancelled = true; };
}, [userId]);
if (!user) return <Loading />;
return <Profile user={user} />;
}For detailed performance patterns, see PERFORMANCE.md.
jsx
function UserProfile({ userId }) {
const [user, setUser] = useState(null);
useEffect(() => {
let cancelled = false;
async function fetchUser() {
const data = await getUser(userId);
if (!cancelled) setUser(data);
}
fetchUser();
return () => { cancelled = true; };
}, [userId]);
if (!user) return <Loading />;
return <Profile user={user} />;
}如需了解详细的性能优化模式,请查看PERFORMANCE.md。