React18+pnpm+Ts+React-Router v6从0-1搭建后台系统

大家好,我是鱼樱!!!

关注公众号【鱼樱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 DesignArco 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;

性能优化策略

  1. 代码分割:使用React.lazy和Suspense进行组件懒加载
  2. 虚拟列表:对长列表使用react-window或react-virtualized
  3. 组件缓存:使用React.memo、useMemo、useCallback避免不必要的重渲染
  4. Web Vitals监控:使用web-vitals库监控核心性能指标
  5. 资源优化:使用现代图片格式(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后台管理系统,推荐以下选择:

  1. 基础技术栈:React 18/19 + TypeScript + pnpm + Vite
  2. 路由:React Router v6
  3. 状态管理
    • 中小型项目:Zustand
    • 大型复杂项目:Redux Toolkit
  4. UI库
    • 企业级后台系统:Ant DesignArco Design
    • 注重定制化:Chakra UI 或基于Tailwind CSS的组件库
  5. 工程化
    • ESLint + Prettier + Husky + Commitlint
    • 自动化测试:Jest + React Testing Library
  6. 构建工具:Vite(比CRA更快的开发体验)

以上最佳实践能够构建出一个现代化、可维护、高性能的React后台管理系统。根据项目具体需求,可以进行适当调整和优化。

哥哥姐姐弟弟妹妹们都看到这里不给个赞👍🏻

相关推荐
小堃学编程11 分钟前
前端学习(2)—— CSS详解与使用
前端·css·学习
蓝婷儿22 分钟前
第一章:HTML基石·现实的骨架
前端·html
Watermelo61730 分钟前
前端如何应对精确数字运算?用BigNumber.js解决JavaScript原生Number类型在处理大数或高精度计算时的局限性
开发语言·前端·javascript·vue.js·前端框架·vue·es6
HebyH_31 分钟前
2025前端面试遇到的问题(vue+uniapp+js+css)
前端·javascript·vue.js·面试·uni-app
Clockwiseee35 分钟前
CSRF记录
前端·csrf
深圳卢先生37 分钟前
XSS 和 CSRF 有什么区别?Java Web 如何防御?
前端·xss·csrf
EndingCoder3 小时前
2025年JavaScript性能优化全攻略
开发语言·javascript·性能优化
qq_386322694 小时前
华为网路设备学习-21 IGP路由专题-路由过滤(filter-policy)
前端·网络·学习
a濯9 小时前
element plus el-table多选框跨页多选保留
javascript·vue.js
蓝婷儿9 小时前
前端面试每日三题 - Day 32
前端·面试·职场和发展