
文章目录
编写 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)
- 一个文件一个组件: 除非是紧密相关的子组件(如
Menu和Menu.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 ( <> - 总是使用自闭合标签: 如果组件没有子内容。
// ✅ 正确// ❌ 错误 - 多属性换行: 如果属性较多,将每个属性单独放一行,闭合标签另起一行。
// ✅ 可读性更高 - 在 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 具有强大的组合模型,通过
props和children来组合组件。// 使用 children 进行内容组合 function Card({ title, children }) { return (); } // 使用 function UserList() { return ({title}
{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 时,useReducer 比 useState 更适用。
```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.lazy 和 Suspense 实现组件级的动态导入,减少初始包体积。
```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.json 或 tsconfig.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 编码规范,将帮助你构建出:
- 清晰可读的代码 (L1)
- 灵活可复用的组件 (L2)
- ** predictable** 的数据流 (L3)
- 隔离无冲突的样式 (L4)
- 高效流畅的用户体验 (L5)
- 可扩展易协作的项目架构 (L6)
规范不是一成不变的教条,应根据团队和项目的具体情况进行调整和采纳。但其核心目标始终不变:提升代码质量、开发效率和应用性能。

浙公网安备 33010602011771号