React + TS 大型后台项目工程化全套实战(React18 + Vite + Redux Toolkit + React Router 6 + AntD)

1 阅读2分钟

一、技术栈选型与项目架构

核心技术栈

  • React18(Hooks API)
  • Vite
  • TypeScript
  • Redux Toolkit(RTK)
  • React Router 6
  • Ant Design
  • Axios 封装
  • ESLint + Prettier + Husky
  • Less / CSS Modules

推荐目录结构

src
├── api         # 接口封装
├── assets      # 静态资源
├── components  # 通用业务组件
├── config      # 环境与常量
├── hooks       # 自定义Hooks
├── layouts     # 布局组件
├── pages       # 业务页面
├── router      # 路由配置
├── store       # Redux Toolkit仓库
├── types       # TS类型声明
├── utils       # 工具函数
├── App.tsx
└── main.tsx

二、Axios 全局请求封装

src/utils/request.ts

import axios from 'axios'
import { message } from 'antd'

// 创建axios实例
const request = axios.create({
  baseURL: import.meta.env.VITE_API_BASE_URL,
  timeout: 10000,
})

// 请求拦截器
request.interceptors.request.use(
  (config) => {
    const token = localStorage.getItem('token')
    if (token) {
      config.headers.Authorization = `Bearer ${token}`
    }
    return config
  },
  (error) => Promise.reject(error)
)

// 响应拦截器
request.interceptors.response.use(
  (response) => response.data,
  (error) => {
    message.error(error.response?.data?.message || '请求失败')
    return Promise.reject(error)
  }
)

export default request

三、Redux Toolkit 状态管理

src/store/index.ts

import { configureStore, createSlice } from '@reduxjs/toolkit'

// 用户模块
const userSlice = createSlice({
  name: 'user',
  initialState: {
    token: localStorage.getItem('token') || '',
    userInfo: null,
  },
  reducers: {
    setToken: (state, action) => {
      state.token = action.payload
      localStorage.setItem('token', action.payload)
    },
    setUserInfo: (state, action) => {
      state.userInfo = action.payload
    },
  },
})

export const { setToken, setUserInfo } = userSlice.actions

// 配置Store
export const store = configureStore({
  reducer: {
    user: userSlice.reducer,
  },
})

四、React Router 6 权限路由

src/router/index.tsx

import { createBrowserRouter, RouterProvider, Navigate } from 'react-router-dom'
import { useSelector } from 'react-redux'

// 页面组件
import Login from '@/pages/Login'
import Home from '@/pages/Home'
import User from '@/pages/User'
import MainLayout from '@/layouts/MainLayout'

// 路由守卫组件
const PrivateRoute = ({ children }: { children: React.ReactNode }) => {
  const { token } = useSelector((state) => state.user)
  return token ? children : <Navigate to="/login" />
}

// 定义路由
const router = createBrowserRouter([
  {
    path: '/',
    element: (
      <PrivateRoute>
        <MainLayout />
      </PrivateRoute>
    ),
    children: [
      { index: true, element: <Home /> },
      { path: 'user', element: <User /> },
    ],
  },
  { path: '/login', element: <Login /> },
])

export default function Routes() {
  return <RouterProvider router={router} />
}

五、React18 性能优化要点

  1. 组件 memo 优化
const Child = React.memo(() => {
  // ...
})
  1. 使用 useMemo 与 useCallback
const computedValue = useMemo(() => { /* 计算逻辑 */ }, [deps])

const handleClick = useCallback(() => { /* 逻辑 */ }, [deps])
  1. React.lazy 与 Suspense 路由懒加载
const Home = React.lazy(() => import('@/pages/Home'))

<Suspense fallback={<div>Loading...</div>}>
  <Home />
</Suspense>

六、典型业务场景实现

1. 分页搜索列表

import { Table, Input, Button, Space } from 'antd'
import { useRequest } from 'ahooks'

const UserList = () => {
  const [searchParams, setSearchParams] = useState({ name: '', current: 1, pageSize: 10 })

  const { data, loading } = useRequest(
    () => request.get('/user/list', { params: searchParams }),
    { refreshDeps: [searchParams] }
  )

  const columns = [
    { title: '姓名', dataIndex: 'name', key: 'name' },
    // 更多列...
  ]

  return (
    <div>
      <Space style={{ marginBottom: 16 }}>
        <Input
          placeholder="用户名"
          value={searchParams.name}
          onChange={(e) => setSearchParams({ ...searchParams, name: e.target.value })}
        />
        <Button onClick={() => setSearchParams({ ...searchParams, current: 1 })}>查询</Button>
      </Space>
      <Table
        columns={columns}
        dataSource={data?.list || []}
        loading={loading}
        pagination={{ total: data?.total || 0, current: searchParams.current, pageSize: searchParams.pageSize }}
        onChange={(page) => setSearchParams({ ...searchParams, current: page.current, pageSize: page.pageSize })}
      />
    </div>
  )
}

七、面试高频考点

  • React18 新特性(Concurrent Mode、自动批处理)
  • React Hooks 规则与闭包陷阱
  • Redux Toolkit 与传统 Redux 对比
  • React Router 6 核心变更(布局路由、loader、action)
  • 性能优化策略(memo、useMemo、useCallback)
  • 状态管理方案对比(Redux、Zustand、Jotai)

——个人观点 · 仅供参考——