大家好,我是鱼樱!!!
关注公众号【鱼樱AI实验室】
持续每天分享更多前端和AI辅助前端编码新知识~~喜欢的就一起学反正开源至上,无所谓被诋毁被喷被质疑文章没有价值~
一个城市淘汰的自由职业-农村前端程序员(虽然不靠代码挣钱,写文章就是为爱发电),兼职远程上班目前!!!热心坚持分享~~~
今天大家分享一个0-1搭建React后台管理系统的最佳实践模板思路~ 并且推荐一个双越老师的划水AI项目 有需要的可以私我走优惠通道~
React18/19 + pnpm + TypeScript + React-Router v6 后台管理系统最佳实践
项目基础搭建
技术栈选择
- React 18/19:使用最新的React版本获取性能提升和新特性
- TypeScript:提供类型安全,提升代码质量和开发体验
- pnpm:比npm/yarn更快的包管理器,节省磁盘空间
- React Router v6:最新版路由,支持嵌套路由和数据加载
- Vite:比Create React App更快的构建工具
项目初始化
bash
# 使用pnpm创建Vite+React+TS项目
pnpm create vite my-admin --template react-ts
# 进入项目目录
cd my-admin
# 安装依赖
pnpm install
# 安装React Router
pnpm add react-router-dom@6
项目目录结构
bash
src/
├── assets/ # 静态资源
├── components/ # 公共组件
├── hooks/ # 自定义hooks
├── layouts/ # 布局组件
├── pages/ # 页面组件
├── services/ # API请求
├── stores/ # 状态管理
├── types/ # 类型定义
├── utils/ # 工具函数
├── App.tsx # 应用入口
└── main.tsx # 渲染入口
代码规范与工程化
ESLint 和 Prettier 配置
bash
# 安装ESLint和Prettier
pnpm add -D eslint prettier eslint-plugin-react eslint-plugin-react-hooks
pnpm add -D @typescript-eslint/eslint-plugin @typescript-eslint/parser
pnpm add -D eslint-config-prettier eslint-plugin-prettier
.eslintrc.js
javascript
module.exports = {
parser: '@typescript-eslint/parser',
extends: [
'eslint:recommended',
'plugin:react/recommended',
'plugin:@typescript-eslint/recommended',
'plugin:react-hooks/recommended',
'plugin:prettier/recommended'
],
plugins: ['react', '@typescript-eslint', 'prettier'],
rules: {
// 自定义规则
'react/react-in-jsx-scope': 'off',
'prettier/prettier': 'error'
}
};
.prettierrc
json
{
"semi": true,
"singleQuote": true,
"tabWidth": 2,
"printWidth": 100,
"trailingComma": "es5"
}
Git 提交规范
bash
# 安装commitlint和husky
pnpm add -D @commitlint/cli @commitlint/config-conventional husky lint-staged
commitlint.config.js
javascript
module.exports = {
extends: ['@commitlint/config-conventional'],
rules: {
'type-enum': [
2,
'always',
['feat', 'fix', 'docs', 'style', 'refactor', 'perf', 'test', 'chore', 'revert']
]
}
};
设置husky
bash
# 初始化husky
npx husky install
# 添加pre-commit钩子
npx husky add .husky/pre-commit "npx lint-staged"
# 添加commit-msg钩子
npx husky add .husky/commit-msg "npx --no -- commitlint --edit $1"
配置lint-staged
json
// package.json
{
"lint-staged": {
"*.{js,jsx,ts,tsx}": [
"eslint --fix",
"prettier --write"
]
}
}
编辑器规范
.editorconfig
ini
root = true
[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false
VSCode设置
创建.vscode/settings.json
:
json
{
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
"typescript.tsdk": "node_modules/typescript/lib",
"typescript.enablePromptUseWorkspaceTsdk": true
}
路由与权限设计
React Router v6 配置
tsx
// src/routes/index.tsx
import { lazy, Suspense } from 'react';
import { Navigate, RouteObject } from 'react-router-dom';
import MainLayout from '@/layouts/MainLayout';
import AuthGuard from '@/components/AuthGuard';
import Loading from '@/components/Loading';
// 懒加载页面
const Dashboard = lazy(() => import('@/pages/Dashboard'));
const UserList = lazy(() => import('@/pages/User/List'));
const UserDetail = lazy(() => import('@/pages/User/Detail'));
const Login = lazy(() => import('@/pages/Login'));
// 路由配置
export const routes: RouteObject[] = [
{
path: '/',
element: <MainLayout />,
children: [
{ index: true, element: <Navigate to="/dashboard" replace /> },
{
path: 'dashboard',
element: (
<AuthGuard requiredPermissions={['dashboard:view']}>
<Suspense fallback={<Loading />}>
<Dashboard />
</Suspense>
</AuthGuard>
)
},
{
path: 'users',
children: [
{
index: true,
element: (
<AuthGuard requiredPermissions={['user:list']}>
<Suspense fallback={<Loading />}>
<UserList />
</Suspense>
</AuthGuard>
)
},
{
path: ':id',
element: (
<AuthGuard requiredPermissions={['user:detail']}>
<Suspense fallback={<Loading />}>
<UserDetail />
</Suspense>
</AuthGuard>
)
}
]
}
]
},
{
path: '/login',
element: (
<Suspense fallback={<Loading />}>
<Login />
</Suspense>
)
},
{ path: '*', element: <Navigate to="/login" replace /> }
];
权限设计
基于RBAC的权限设计
tsx
// src/components/AuthGuard.tsx
import { ReactNode } from 'react';
import { Navigate } from 'react-router-dom';
import { useAuth } from '@/hooks/useAuth';
interface AuthGuardProps {
children: ReactNode;
requiredPermissions?: string[];
}
const AuthGuard = ({ children, requiredPermissions = [] }: AuthGuardProps) => {
const { isAuthenticated, hasPermissions } = useAuth();
if (!isAuthenticated) {
return <Navigate to="/login" replace />;
}
if (requiredPermissions.length > 0 && !hasPermissions(requiredPermissions)) {
return <Navigate to="/403" replace />;
}
return <>{children}</>;
};
export default AuthGuard;
权限相关的Hook
tsx
// src/hooks/useAuth.ts
import { useCallback } from 'react';
import { useAuthStore } from '@/stores/authStore';
export const useAuth = () => {
const { user, permissions, setUser, logout } = useAuthStore();
const isAuthenticated = !!user;
const hasPermissions = useCallback(
(requiredPermissions: string[]) => {
if (!permissions || permissions.length === 0) return false;
return requiredPermissions.every(permission => permissions.includes(permission));
},
[permissions]
);
return {
user,
isAuthenticated,
permissions,
hasPermissions,
setUser,
logout
};
};
状态管理:Zustand vs Redux
比较
特性 | Zustand | Redux (Redux Toolkit) |
---|---|---|
上手难度 | 简单 | 中等 |
样板代码 | 少 | 中等 (RTK减少了大量样板代码) |
体积 | 轻量 | 较重 |
中间件支持 | 有,但不太丰富 | 丰富 |
开发工具 | 有基础支持 | 强大 |
异步处理 | 直接支持 | 需要RTK Query或thunk |
社区生态 | 成长中 | 成熟 |
选择建议
- Zustand:适合中小型项目,需要快速开发,简单状态管理
- Redux:适合大型项目,有复杂状态逻辑,需要强大的调试工具和中间件支持
Zustand最佳实践
typescript
// src/stores/authStore.ts
import { create } from 'zustand';
import { persist } from 'zustand/middleware';
interface User {
id: string;
name: string;
}
interface AuthState {
user: User | null;
permissions: string[];
setUser: (user: User, permissions: string[]) => void;
logout: () => void;
}
export const useAuthStore = create<AuthState>()(
persist(
(set) => ({
user: null,
permissions: [],
setUser: (user, permissions) => set({ user, permissions }),
logout: () => set({ user: null, permissions: [] })
}),
{
name: 'auth-storage'
}
)
);
typescript
// src/stores/userStore.ts
import { create } from 'zustand';
import { fetchUsers } from '@/services/userService';
interface UserState {
users: any[];
loading: boolean;
error: string | null;
fetchUsers: () => Promise<void>;
}
export const useUserStore = create<UserState>((set) => ({
users: [],
loading: false,
error: null,
fetchUsers: async () => {
set({ loading: true, error: null });
try {
const data = await fetchUsers();
set({ users: data, loading: false });
} catch (error) {
set({ error: (error as Error).message, loading: false });
}
}
}));
Redux Toolkit最佳实践
typescript
// src/stores/slices/authSlice.ts
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
interface User {
id: string;
name: string;
}
interface AuthState {
user: User | null;
permissions: string[];
}
const initialState: AuthState = {
user: null,
permissions: []
};
export const authSlice = createSlice({
name: 'auth',
initialState,
reducers: {
setUser: (state, action: PayloadAction<{ user: User; permissions: string[] }>) => {
state.user = action.payload.user;
state.permissions = action.payload.permissions;
},
logout: (state) => {
state.user = null;
state.permissions = [];
}
}
});
export const { setUser, logout } = authSlice.actions;
export default authSlice.reducer;
typescript
// src/stores/slices/userSlice.ts
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';
import { fetchUsers } from '@/services/userService';
export const fetchUsersThunk = createAsyncThunk('users/fetchUsers', async () => {
const response = await fetchUsers();
return response;
});
const userSlice = createSlice({
name: 'users',
initialState: {
data: [],
loading: false,
error: null
},
reducers: {},
extraReducers: (builder) => {
builder
.addCase(fetchUsersThunk.pending, (state) => {
state.loading = true;
state.error = null;
})
.addCase(fetchUsersThunk.fulfilled, (state, action) => {
state.data = action.payload;
state.loading = false;
})
.addCase(fetchUsersThunk.rejected, (state, action) => {
state.loading = false;
state.error = action.error.message || 'Failed to fetch users';
});
}
});
export default userSlice.reducer;
UI库选择
主流UI库对比
UI库 | 优点 | 缺点 | 适用场景 |
---|---|---|---|
Ant Design | 组件丰富,企业级,生态成熟 | 体积较大,定制化需要额外工作 | 后台管理系统,企业应用 |
Material UI | 设计精美,响应式,支持深度定制 | 学习曲线略陡,体积较大 | 需要精美UI的应用,偏向Google设计风格 |
Chakra UI | 轻量级,易于定制,响应式 | 组件相对较少 | 中小型项目,需要高度定制化 |
Tailwind UI | 高度可定制,不限制组件结构 | 需要自己实现交互逻辑 | 需要独特设计的项目 |
Arco Design | 轻量级,性能优秀,全局配置便捷 | 社区相对较小 | 注重性能的后台系统 |
推荐选择
对于后台管理系统,推荐Ant Design 或Arco Design:
bash
# 安装Ant Design
pnpm add antd @ant-design/icons
# 或者安装Arco Design
pnpm add @arco-design/web-react @arco-design/icon
API请求封装
使用Axios封装
bash
pnpm add axios
typescript
// src/utils/request.ts
import axios, { AxiosRequestConfig, AxiosResponse, AxiosError } from 'axios';
import { message } from 'antd';
import { useAuthStore } from '@/stores/authStore';
const service = axios.create({
baseURL: import.meta.env.VITE_API_BASE_URL,
timeout: 10000
});
// 请求拦截器
service.interceptors.request.use(
(config) => {
const token = useAuthStore.getState().user?.token;
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
},
(error) => {
return Promise.reject(error);
}
);
// 响应拦截器
service.interceptors.response.use(
(response: AxiosResponse) => {
const { data } = response;
// 根据实际后端接口结构调整
if (data.code !== 0) {
message.error(data.message || '请求错误');
// 处理特定的错误码
if (data.code === 401) {
useAuthStore.getState().logout();
}
return Promise.reject(new Error(data.message || '请求错误'));
}
return data.data;
},
(error: AxiosError) => {
if (error.response) {
const status = error.response.status;
let errorMsg = '未知错误';
if (status === 401) {
errorMsg = '未授权,请重新登录';
useAuthStore.getState().logout();
} else if (status === 403) {
errorMsg = '拒绝访问';
} else if (status === 404) {
errorMsg = '请求的资源不存在';
} else if (status === 500) {
errorMsg = '服务器错误';
}
message.error(errorMsg);
} else {
message.error('网络错误,请检查您的网络连接');
}
return Promise.reject(error);
}
);
// 封装GET请求
export function get<T>(url: string, params?: any, config?: AxiosRequestConfig): Promise<T> {
return service.get(url, { params, ...config });
}
// 封装POST请求
export function post<T>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T> {
return service.post(url, data, config);
}
// 封装其他请求方法
export function put<T>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T> {
return service.put(url, data, config);
}
export function del<T>(url: string, config?: AxiosRequestConfig): Promise<T> {
return service.delete(url, config);
}
export default service;
性能优化策略
- 代码分割:使用React.lazy和Suspense进行组件懒加载
- 虚拟列表:对长列表使用react-window或react-virtualized
- 组件缓存:使用React.memo、useMemo、useCallback避免不必要的重渲染
- Web Vitals监控:使用web-vitals库监控核心性能指标
- 资源优化:使用现代图片格式(WebP),合理使用CDN
typescript
// src/hooks/useVirtualScroll.ts
import { useState, useRef, useEffect } from 'react';
export function useVirtualScroll<T>(items: T[], itemHeight: number, containerHeight: number) {
const [scrollTop, setScrollTop] = useState(0);
const containerRef = useRef<HTMLDivElement>(null);
const visibleItemCount = Math.ceil(containerHeight / itemHeight) + 2;
const startIndex = Math.floor(scrollTop / itemHeight);
const endIndex = Math.min(startIndex + visibleItemCount, items.length);
const visibleItems = items.slice(startIndex, endIndex);
const totalHeight = items.length * itemHeight;
const offsetY = startIndex * itemHeight;
useEffect(() => {
const handleScroll = () => {
if (containerRef.current) {
setScrollTop(containerRef.current.scrollTop);
}
};
const container = containerRef.current;
container?.addEventListener('scroll', handleScroll);
return () => container?.removeEventListener('scroll', handleScroll);
}, []);
return {
containerRef,
visibleItems,
totalHeight,
offsetY,
};
}
总结
搭建一个现代化的React后台管理系统,推荐以下选择:
- 基础技术栈:React 18/19 + TypeScript + pnpm + Vite
- 路由:React Router v6
- 状态管理 :
- 中小型项目:Zustand
- 大型复杂项目:Redux Toolkit
- UI库 :
- 企业级后台系统:Ant Design 或Arco Design
- 注重定制化:Chakra UI 或基于Tailwind CSS的组件库
- 工程化 :
- ESLint + Prettier + Husky + Commitlint
- 自动化测试:Jest + React Testing Library
- 构建工具:Vite(比CRA更快的开发体验)
以上最佳实践能够构建出一个现代化、可维护、高性能的React后台管理系统。根据项目具体需求,可以进行适当调整和优化。
哥哥姐姐弟弟妹妹们都看到这里不给个赞👍🏻