在这里插入图片描述

编写 React 代码不仅仅是让功能跑起来,更重要的是保证代码的可读性、可维护性和团队协作效率。一套良好的编码规范是达成这些目标的基石。本文将从基础规范组件设计状态管理样式处理性能优化项目架构六个层次,由浅入深地详解 React 的代码编写规范,并提供大量代码示例和一张全面的六层架构图。


一、 核心六层规范架构图

在深入细节之前,我们先通过一张图来总览 React 代码规范的六个核心层次,它们构成了一个完整、健壮的应用开发体系:

flowchart TD
    A[React 代码规范六层体系]
    A --> B[L1: 基础与核心规范
命名、文件组织、JSX、PropTypes] A --> C[L2: 组件设计模式
组件拆分、组合、解耦] A --> D[L3: 状态管理规范
State原则、Reducer、Context、Redux] A --> E[L4: 样式与CSS策略
CSS Modules、Styled-Components、方案选型] A --> F[L5: 性能优化指南
Memo、Callback、懒加载、列表优化] A --> G[L6: 项目结构与架构
目录组织、路由、配置、静态资源] B --> H[目标: 代码一致性与可读性] C --> I[目标: 可复用与可维护性] D --> J[目标: 数据流清晰与可预测] E --> K[目标: 样式可控与避免冲突] F --> L[目标: 应用流畅与用户体验] G --> M[目标: 项目可扩展与易于协作]

二、 L1 - 基础与核心规范 (Foundation & Core)

这是最基础也是必须遵守的规范,保证了代码的一致性和可读性。

1. 命名规范 (Naming Conventions)

  • 组件命名: 使用 PascalCase (大驼峰命名法),且名称与文件名一致。
    // ✅ 正确
    // UserProfile.jsx
    function UserProfile() { ... }
    // ❌ 错误
    // userProfile.jsx
    function user_profile() { ... }
    function User_Profile() { ... }
  • 属性命名: 使用 camelCase (小驼峰命名法)。
    // ✅ 正确
    
  • 自定义事件处理函数: 以 handle 开头,后接事件名或操作名。
    const handleInputChange = () => { ... };
    const handleSubmit = () => { ... };
  • 布尔型 Props: 前缀使用 is, has, should 等,使其语义更明确。

2. 文件组织 (File Organization)

  • 一个文件一个组件: 除非是紧密相关的子组件(如 MenuMenu.Item),否则每个文件应只导出一个组件。
  • 文件扩展名: 使用 .jsx.tsx 用于组件文件,以明确区分包含 JSX 的代码。工具函数等纯 JavaScript 文件使用 .js.ts
  • 组件与样式、逻辑分离: 鼓励将样式文件(如 .module.css)和逻辑文件(如 hooks.js)放在同一目录下。
    src/
      components/
        UserProfile/
          index.jsx       # 主组件,只做导入和导出,保持整洁
          UserProfile.jsx # 组件实现
          UserProfile.module.css
          hooks.js        # 自定义hooks,如useUserData
          constants.js    # 常量定义

3. JSX 编写规范

  • 始终返回单个根元素: 使用 <></> 片段 (Fragment) 或多个标签包裹。
    // ✅ 正确
    return (
      <>
        
    ); // ❌ 错误 return (
    );
  • 总是使用自闭合标签: 如果组件没有子内容。
    // ✅ 正确
    
    // ❌ 错误
    
  • 多属性换行: 如果属性较多,将每个属性单独放一行,闭合标签另起一行。
    // ✅ 可读性更高
    
  • 在 JSX 中使用 JavaScript 表达式时用 {} 包裹

4. Props 类型检查 (PropTypes / TypeScript)

  • 必须为组件 props 定义类型,这能极大提高代码健壮性和开发体验。

  • 使用 TypeScript (首选)prop-types 库。

    TypeScript:

    interface UserCardProps {
      name: string;
      age: number;
      isActive?: boolean; // 可选属性
      onEdit: (id: number) => void;
    }
    const UserCard: React.FC = ({ name, age, isActive = false, onEdit }) => { ... };

    PropTypes (无TS时):

    import PropTypes from 'prop-types';
    const UserCard = ({ name, age, isActive, onEdit }) => { ... };
    UserCard.propTypes = {
      name: PropTypes.string.isRequired,
      age: PropTypes.number.isRequired,
      isActive: PropTypes.bool,
      onEdit: PropTypes.func.isRequired,
    };
    UserCard.defaultProps = {
      isActive: false,
    };

三、 L2 - 组件设计模式 (Component Design Patterns)

1. 组件拆分与组合 (Component Splitting & Composition)

  • 单一职责原则: 一个组件只负责一个功能。过大的组件应拆分为更小的、可复用的子组件。

  • 优先使用组合而非继承: React 具有强大的组合模型,通过 propschildren 来组合组件。

    // 使用 children 进行内容组合
    function Card({ title, children }) {
      return (
        

    {title}

    {children}
    {/* 内容插槽 */}
    ); } // 使用 function UserList() { return (
      ...
    {/* 这里的内容就是 children */}
    ); } // 使用特定 props 进行组合 function Layout({ header, sidebar, content }) { return (
    {header}
    {sidebar}
    {content}
    ); } // 使用 } sidebar={} content={} />

2. 展示组件与容器组件 (Presentational vs Container Components)

这是一种逻辑分离的模式,鼓励将UI渲染业务逻辑/状态管理解耦。

展示组件 (Presentational)容器组件 (Container)
目的看起来是什么样子 (UI, 样式)如何工作 (数据获取, 状态更新)
是否感知 Redux
数据来源Props订阅 Redux State, 发起 Actions
编写方式多为函数组件多为类组件(过去)或使用 Hooks 的函数组件
复用性

示例:

// Presentation Component: 只负责展示,非常纯净
function UserList({ users, isLoading, onUserClick }) {
  if (isLoading) return 
Loading...
; return (
    {users.map(user => (
  • onUserClick(user.id)}> {user.name}
  • ))}
); } // Container Component: 负责管理数据和逻辑 import { useSelector, useDispatch } from 'react-redux'; import { fetchUsers, selectUsers } from './userSlice'; function UserListContainer() { const dispatch = useDispatch(); const { users, isLoading } = useSelector(selectUsers); useEffect(() => { dispatch(fetchUsers()); }, [dispatch]); const handleUserClick = (userId) => { ... }; // 将状态和逻辑作为Props传递给展示组件 return ( ); }

四、 L3 - 状态管理规范 (State Management)

1. State 放置原则

  • 状态提升: 如果多个组件需要反映相同的变化数据,应将共享状态提升到最近的共同父组件中。

  • 保持状态最小化: 不要存储冗余状态或可由其他 state/props 计算得出的值。

    // ❌ 冗余状态
    const [firstName, setFirstName] = useState('');
    const [lastName, setLastName] = useState('');
    const [fullName, setFullName] = useState(''); // 可由firstName和lastName计算得出
    // ✅ 派生状态
    const [firstName, setFirstName] = useState('');
    const [lastName, setLastName] = useState('');
    const fullName = `${firstName} ${lastName}`; // 直接计算

2. 使用 useReducer 管理复杂状态

当 state 逻辑复杂,包含多个子值,或者下一个 state 依赖于之前的 state 时,useReduceruseState 更适用。

```jsx
const initialState = { count: 0 };
function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return { count: state.count + 1 };
    case 'decrement':
      return { count: state.count - 1 };
    case 'reset':
      return initialState;
    default:
      throw new Error();
  }
}
function Counter() {
  const [state, dispatch] = useReducer(reducer, initialState);
  return (
    <>
      Count: {state.count}
      
      
      
    
  );
}
```

3. 全局状态管理 (Redux Toolkit 最佳实践)

对于复杂的跨组件状态,推荐使用 Redux Toolkit (RTK),它简化了 Redux 的传统繁琐流程。

```jsx
// store/userSlice.js
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';
export const fetchUsers = createAsyncThunk('users/fetchUsers', async () => {
  const response = await fetch('/api/users');
  return response.json();
});
const userSlice = createSlice({
  name: 'users',
  initialState: { entities: [], loading: 'idle' },
  reducers: {
    // 同步actions
    userAdded(state, action) {
      state.entities.push(action.payload);
    },
  },
  extraReducers: (builder) => {
    // 处理异步thunk actions
    builder
      .addCase(fetchUsers.pending, (state) => {
        state.loading = 'pending';
      })
      .addCase(fetchUsers.fulfilled, (state, action) => {
        state.loading = 'idle';
        state.entities = action.payload;
      });
  },
});
export const { userAdded } = userSlice.actions;
export default userSlice.reducer;
```

五、 L4 - 样式与 CSS 策略 (Styling & CSS Strategies)

1. CSS Modules (推荐)

CSS Modules 是局部作用域 CSS 的完美解决方案,可以避免类名冲突。

```css
/* Button.module.css */
.primary { /* 编译后会被哈希化,如 .primary__1s2dx */
  background-color: blue;
  color: white;
}
.size-large {
  padding: 10px 20px;
}
```
```jsx
// Button.jsx
import styles from './Button.module.css'; // 导入为一个styles对象
const Button = ({ variant, size, children }) => {
  // 动态组合类名
  const buttonClass = `${styles.button} ${styles[variant]} ${styles[`size-${size}`]}`;
  return (
    
  );
};
```

2. Styled-Components (CSS-in-JS)

允许你在 JavaScript 中编写实际的 CSS 代码来样式化组件。

```jsx
import styled from 'styled-components';
const StyledButton = styled.button`
  background-color: ${props => props.primary ? 'blue' : 'white'};
  color: ${props => props.primary ? 'white' : 'blue'};
  padding: ${props => {
    if (props.size === 'large') return '10px 20px';
    if (props.size === 'small') return '5px 10px';
    return '8px 16px';
  }};
  border: 2px solid blue;
  border-radius: 3px;
  cursor: pointer;
  &:hover {
    opacity: 0.9;
  }
`;
function MyComponent() {
  return (
    
普通按钮 主要大按钮
); } ```

六、 L5 - 性能优化指南 (Performance Optimization)

1. 避免不必要的重新渲染

  • React.memo: 用于缓存函数组件,仅在 props 变化时重新渲染。
    const MyExpensiveComponent = React.memo(function MyComponent({ data }) {
      // ...
    }, arePropsEqual?); // 可自定义比较函数
  • useCallback: 缓存函数,避免因函数引用变化导致子组件不必要的渲染。常用于传递给子组件的事件处理函数。
    const handleClick = useCallback(() => {
      setCount(c => c + 1);
    }, []); // 依赖项为空数组,函数只创建一次
  • useMemo: 缓存昂贵的计算结果。只有在依赖项改变时才会重新计算。
    const sortedList = useMemo(() => {
      return myLargeList.sort((a, b) => a.name.localeCompare(b.name));
    }, [myLargeList]); // 只有当 myLargeList 变化时才重新排序

2. 代码分割与懒加载 (Lazy Loading)

使用 React.lazySuspense 实现组件级的动态导入,减少初始包体积。

```jsx
import React, { Suspense } from 'react';
const LazyComponent = React.lazy(() => import('./LazyComponent'));
function App() {
  return (
    
Loading...
}>
); } ```

3. 列表渲染优化

  • 始终使用稳定的、唯一的 key,绝不要用数组索引 index
    {items.map(item => (
       // ✅ 使用唯一ID
    ))}
  • 对超长列表使用虚拟滚动库(如 react-window)。

七、 L6 - 项目结构与架构 (Project Structure & Architecture)

1. 功能分区目录结构 (Feature-Based Structure)

对于中型及以上项目,推荐按功能/模块来组织目录,而不是按“文件类型”(如 components/, pages/)。

```
src/
  features/
    auth/           # 认证功能模块
      components/   # 该功能专用的组件
      hooks/        # 该功能专用的hooks
      slice.js      # Redux slice (如果用了Redux)
      index.js      # 统一出口
    dashboard/      # 仪表盘功能模块
      components/
      hooks/
      ...
  common/           # 全局共享内容
    components/     # 通用组件 (Button, Modal, Layout)
    hooks/          # 通用hooks (useLocalStorage)
    utils/          # 工具函数
  app/
    store.js        # Redux store配置
    routes.js       # 路由配置
  App.jsx
  index.js
```

2. 使用绝对路径导入

配置 jsconfig.jsontsconfig.json 来避免复杂的相对路径 ../../../

```json
// jsconfig.json
{
  "compilerOptions": {
    "baseUrl": "src"
  },
  "include": ["src"]
}
```
配置后,导入方式变得更清晰:
```jsx
// ✅ 清晰
import Button from 'common/components/Button';
import { fetchUsers } from 'features/users/userSlice';
// ❌ 混乱
import Button from '../../../../common/components/Button';
```

总结

遵循以上六个层次的 React 编码规范,将帮助你构建出:

  1. 清晰可读的代码 (L1)
  2. 灵活可复用的组件 (L2)
  3. ** predictable** 的数据流 (L3)
  4. 隔离无冲突的样式 (L4)
  5. 高效流畅的用户体验 (L5)
  6. 可扩展易协作的项目架构 (L6)

规范不是一成不变的教条,应根据团队和项目的具体情况进行调整和采纳。但其核心目标始终不变:提升代码质量、开发效率和应用性能。

在这里插入图片描述