react-guidelines

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

React 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 use
    strict: true
    in
    tsconfig.json
    . avoiding
    any
    ensures type safety.
  • 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: Use
    useMemo
    only if the calculation is computationally expensive.
  • 避免冗余状态不要存储可以从现有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
    useState
    for simple, independent values.
  • Use
    useReducer
    for complex state logic, or when the next state depends on the previous one in complex ways.
  • 对于简单、独立的值,使用
    useState
  • 对于复杂的状态逻辑,或者下一个状态依赖于前一个状态的复杂场景,使用
    useReducer

4. useEffect Usage and Pitfalls

4. useEffect的使用与陷阱

  • Synchronization, Not Data Flow:
    useEffect
    is for synchronizing with external systems (APIs, DOM, subscriptions). It is not for transforming data or "watching" props to update state.
  • 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.
  • 用于同步,而非数据流
    useEffect
    用于与外部系统(API、DOM、订阅)同步。不要用它来转换数据或“监听”props以更新状态。
  • 数据获取:获取数据时,要处理竞态条件(例如,组件卸载或查询条件变化时忽略返回结果)。
  • 严格依赖项:始终将effect中使用的所有变量包含在依赖数组中。
  • 清理函数:对于创建订阅或事件监听器的effect,始终返回清理函数。

5. Component Patterns

5. 组件模式

  • Custom Hooks: Extract logic into custom hooks (
    useUser
    ,
    useWindowSize
    ). This keeps components focused on UI.
  • 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
    useWindowSize
    )。这能让组件专注于UI展示。
  • 容器/展示组件:虽然现在严格分离两者的做法已不常见,但将逻辑复杂的数据获取组件与纯UI组件分离仍然是良好实践。
  • 片段(Fragments):使用
    <>
    (片段)来避免不必要的DOM包装节点。

6. Performance

6. 性能优化

  • Stable Identity: Wrap functions passed as props in
    useCallback
    only if the child component is wrapped in
    React.memo
    or if the function is a dependency of minimal effect.
  • Lists: Always use a unique, stable
    key
    for list items. Do not use array index.
  • Lazy Loading: Use
    React.lazy
    and
    Suspense
    for route-level code splitting.
  • 稳定标识:仅当子组件被
    React.memo
    包裹,或者函数是某个effect的依赖项时,才使用
    useCallback
    包裹作为props传递的函数。
  • 列表渲染:始终为列表项使用唯一、稳定的
    key
    。不要使用数组索引作为key。
  • 懒加载:使用
    React.lazy
    Suspense
    实现路由级别的代码分割。