react-guidelines
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseReact Guidelines
React开发准则
This document outlines best practices for building robust, maintainable, and modern React applications with TypeScript.
本文档概述了使用TypeScript构建健壮、可维护且现代化的React应用的最佳实践。
1. General Principles
1. 通用原则
- Component Composition: Build small, focused components and compose them to build complex UIs.
- Unidirectional Data Flow: Data flows down (props), actions flow up (callbacks).
- Immutability: Treat state as immutable. Use functional updates and immutable patterns.
- Colocation: Keep related logic, styles, and tests close to the component.
- 组件组合:构建小巧、职责单一的组件,通过组合它们来搭建复杂UI。
- 单向数据流:数据向下传递(通过props),操作向上传递(通过回调函数)。
- 不可变性:将状态视为不可变数据。使用函数式更新和不可变模式。
- 就近原则:将相关的逻辑、样式和测试代码放在靠近组件的位置。
2. TypeScript Integration
2. TypeScript集成
-
Strict Typing: Always usein
strict: true. avoidingtsconfig.jsonensures type safety.any -
Props Interfaces: Define explicit interfaces for component props.tsx
interface ButtonProps { label: string; onClick: () => void; variant?: 'primary' | 'secondary'; } -
Discriminated Unions: Use discriminated unions for state that can be in distinct modes (e.g., handling loading/success/error states).tsx
type State = | { status: 'idle' } | { status: 'loading' } | { status: 'success'; data: User } | { status: 'error'; error: Error }; -
Event Types: Use React's built-in event types (e.g.,,
React.ChangeEvent<HTMLInputElement>).React.FormEvent
-
严格类型检查:始终在中设置
tsconfig.json。避免使用strict: true类型以确保类型安全。any -
Props接口:为组件的props定义明确的接口。tsx
interface ButtonProps { label: string; onClick: () => void; variant?: 'primary' | 'secondary'; } -
可辨识联合:使用可辨识联合来处理具有不同状态模式的场景(例如,处理加载/成功/错误状态)。tsx
type State = | { status: 'idle' } | { status: 'loading' } | { status: 'success'; data: User } | { status: 'error'; error: Error }; -
事件类型:使用React内置的事件类型(例如、
React.ChangeEvent<HTMLInputElement>)。React.FormEvent
3. State Management Best Practices
3. 状态管理最佳实践
Derived State (Crucial)
派生状态(关键)
-
Avoid Redundant State: Do not store state that can be calculated from existing props or other state.
-
Calculate on Render: Compute values directly in the component body.
-
Bad:tsx
const [filteredList, setFilteredList] = useState([]); // This is an anti-pattern: syncing state useEffect(() => { setFilteredList(items.filter(i => i.active)); }, [items]); -
Good:tsx
// Calculated during render. Always fresh, no sync bugs. const filteredList = items.filter(i => i.active);
-
-
Memoization: Useonly if the calculation is computationally expensive.
useMemo
-
避免冗余状态:不要存储可以从现有props或其他状态计算得出的数据。
-
在渲染时计算:直接在组件内部计算所需值。
-
不良实践:tsx
const [filteredList, setFilteredList] = useState([]); // 这是反模式:同步状态 useEffect(() => { setFilteredList(items.filter(i => i.active)); }, [items]); -
推荐实践:tsx
// 在渲染时计算。始终保持最新,无同步问题。 const filteredList = items.filter(i => i.active);
-
-
记忆化:仅当计算过程非常耗时的时候才使用。
useMemo
useState vs useReducer
useState vs useReducer
- Use for simple, independent values.
useState - Use for complex state logic, or when the next state depends on the previous one in complex ways.
useReducer
- 对于简单、独立的值,使用。
useState - 对于复杂的状态逻辑,或者下一个状态依赖于前一个状态的复杂场景,使用。
useReducer
4. useEffect Usage and Pitfalls
4. useEffect的使用与陷阱
- Synchronization, Not Data Flow: is for synchronizing with external systems (APIs, DOM, subscriptions). It is not for transforming data or "watching" props to update state.
useEffect - Fetching Data: When fetching data, handle race conditions (e.g., ignore results if the component unmounts or the query changes).
- Strict Dependencies: Always include all variables used in the effect in the dependency array.
- Cleanup Functions: Always return a cleanup function for effects that create subscriptions or event listeners.
- 用于同步,而非数据流:用于与外部系统(API、DOM、订阅)同步。不要用它来转换数据或“监听”props以更新状态。
useEffect - 数据获取:获取数据时,要处理竞态条件(例如,组件卸载或查询条件变化时忽略返回结果)。
- 严格依赖项:始终将effect中使用的所有变量包含在依赖数组中。
- 清理函数:对于创建订阅或事件监听器的effect,始终返回清理函数。
5. Component Patterns
5. 组件模式
- Custom Hooks: Extract logic into custom hooks (,
useUser). This keeps components focused on UI.useWindowSize - Container/Presentational: While strictly rigidly separating them is less common now, separating logically complex data-fetching components from pure UI components is still good practice.
- Fragments: Use (Fragments) to avoid unnecessary DOM wrapper nodes.
<>
- 自定义Hooks:将逻辑提取到自定义Hooks中(如、
useUser)。这能让组件专注于UI展示。useWindowSize - 容器/展示组件:虽然现在严格分离两者的做法已不常见,但将逻辑复杂的数据获取组件与纯UI组件分离仍然是良好实践。
- 片段(Fragments):使用(片段)来避免不必要的DOM包装节点。
<>
6. Performance
6. 性能优化
- Stable Identity: Wrap functions passed as props in only if the child component is wrapped in
useCallbackor if the function is a dependency of minimal effect.React.memo - Lists: Always use a unique, stable for list items. Do not use array index.
key - Lazy Loading: Use and
React.lazyfor route-level code splitting.Suspense
- 稳定标识:仅当子组件被包裹,或者函数是某个effect的依赖项时,才使用
React.memo包裹作为props传递的函数。useCallback - 列表渲染:始终为列表项使用唯一、稳定的。不要使用数组索引作为key。
key - 懒加载:使用和
React.lazy实现路由级别的代码分割。Suspense