Appearance
React 规范
学习地址
基本规则
- 每个文件只包含一个 React 组件,但允许多个无状态组件存在于同一文件
- 始终使用 JSX 语法,不要使用
React.createElement - 推荐使用函数组件 + Hooks,避免使用 Class 组件
项目结构
src
├── api 接口管理
│ └── 业务模块.ts
├── assets 静态资源
│ ├── images
│ └── styles
├── components 公共组件
│ └── CompName
│ ├── index.tsx
│ └── index.module.scss
├── hooks 自定义 Hooks
│ └── useXxx.ts
├── pages / views 页面组件
│ └── PageName
│ ├── index.tsx
│ ├── index.module.scss
│ └── components 页面私有组件
├── router 路由配置
│ └── index.tsx
├── store 状态管理
│ ├── index.ts
│ └── modules
├── utils 工具函数
│ └── request.ts
├── types 类型定义
│ └── index.d.ts
├── App.tsx
└── main.tsx组件命名
- 组件文件:使用 PascalCase(大驼峰),如
UserProfile.tsx - 组件目录:使用 PascalCase,如
UserProfile/index.tsx - 组件实例:使用 camelCase(小驼峰),如
const userProfile = <UserProfile />
tsx
// 推荐
import UserProfile from "./UserProfile";
// 不推荐
import userProfile from "./UserProfile";
import User_Profile from "./User_Profile";JSX 规范
标签与缩进
tsx
// 推荐:多行 JSX 用括号包裹
return (
<div className="container">
<Header />
<Main />
</div>
);
// 不推荐
return (
<div className="container">
<Header />
<Main />
</div>
);属性规范
- 属性使用 camelCase
- 属性值为
true时可省略值 - 使用双引号给 JSX 属性值,使用单引号给 JS 代码
tsx
// 推荐
<Input type="text" disabled onChange={handleChange} />
// 不推荐
<Input type='text' disabled={true} onChange={handleChange} />- 属性较多时换行书写,每个属性占一行
tsx
// 推荐
<UserProfile
className="user-profile"
name={userName}
age={userAge}
onEdit={handleEdit}
/>
// 不推荐
<UserProfile className="user-profile" name={userName} age={userAge} onEdit={handleEdit} />Key 属性
列表渲染必须添加唯一的 key,禁止使用数组索引作为 key:
tsx
// 推荐
{
list.map((item) => <ListItem key={item.id} data={item} />);
}
// 不推荐
{
list.map((item, index) => <ListItem key={index} data={item} />);
}Hooks 规范
基本原则
- 只在函数组件的最顶层调用 Hooks,不要在循环、条件或嵌套函数中调用
- 只在 React 函数组件或自定义 Hooks 中调用 Hooks
- 自定义 Hooks 必须以
use开头命名
tsx
// 推荐
function useUserInfo(userId: string) {
const [user, setUser] = useState(null);
useEffect(() => {
fetchUser(userId).then(setUser);
}, [userId]);
return user;
}
// 不推荐:没有以 use 开头
function getUserInfo(userId: string) {
const [user, setUser] = useState(null);
// ...
}useEffect 使用规范
- 必须正确声明依赖项数组
- 有副作用清理需求时,返回清理函数
- 避免在
useEffect中直接修改 DOM
tsx
// 推荐
useEffect(() => {
const timer = setInterval(() => {
setCount((c) => c + 1);
}, 1000);
return () => clearInterval(timer); // 清理副作用
}, []);
// 不推荐:缺少依赖项 / 缺少清理
useEffect(() => {
setInterval(() => {
setCount(count + 1);
}, 1000);
});useState 使用规范
tsx
// 推荐:语义化命名
const [isLoading, setIsLoading] = useState(false);
const [userList, setUserList] = useState<User[]>([]);
// 不推荐
const [flag, setFlag] = useState(false);
const [data, setData] = useState([]);事件处理
- 事件处理函数以
handle开头命名 - 传递给子组件的回调以
on开头命名
tsx
// 父组件
function ParentComponent() {
const handleItemClick = (id: string) => {
// 处理点击
};
return <ChildComponent onItemClick={handleItemClick} />;
}
// 子组件
interface ChildProps {
onItemClick: (id: string) => void;
}
function ChildComponent({ onItemClick }: ChildProps) {
return <div onClick={() => onItemClick("1")}>Click me</div>;
}TypeScript 规范
- 组件 Props 使用
interface定义,以Props结尾 - 导出类型使用
type或interface - 避免使用
any,尽量使用明确的类型
tsx
// 推荐
interface UserCardProps {
name: string;
age: number;
avatar?: string;
onEdit: (id: string) => void;
}
function UserCard({ name, age, avatar, onEdit }: UserCardProps) {
return (
<div className="user-card">
{avatar && <img src={avatar} alt={name} />}
<span>{name}</span>
<span>{age}</span>
</div>
);
}
// 不推荐
function UserCard(props: any) {
return <div>{props.name}</div>;
}状态管理
推荐使用以下状态管理方案(按项目复杂度选择):
| 方案 | 适用场景 |
|---|---|
useState / useReducer | 组件内部简单状态 |
Context API | 少量全局共享状态 |
Zustand | 中小型项目全局状态管理 |
Redux Toolkit | 大型复杂项目 |
性能优化
- React.memo:对纯展示组件使用
React.memo避免不必要的重渲染 - useMemo / useCallback:缓存计算结果和回调函数
- 懒加载:使用
React.lazy+Suspense实现路由懒加载
tsx
// 路由懒加载
const UserPage = React.lazy(() => import("./pages/User"));
function App() {
return (
<Suspense fallback={<Loading />}>
<UserPage />
</Suspense>
);
}- 避免在渲染中创建新对象/函数:
tsx
// 推荐
const style = useMemo(() => ({ color: 'red', fontSize: 14 }), [])
// 不推荐:每次渲染都创建新对象
<div style={{ color: 'red', fontSize: 14 }} />