3. Web 前端技术选型:React/Vue 框架对比、UI 组件库选择、状态管理方案

在自助容量压测作业平台中,Web 前端承担着任务编排、实时监控、报告展示等核心交互。选型需兼顾开发效率、生态成熟度、团队技术栈与长期维护成本。本章从框架、UI 组件库、状态管理三个维度进行技术选型分析。

3.1 框架选型:React vs Vue 3

React 与 Vue 3 均为当前主流前端框架,但在设计哲学、数据流、渲染机制上存在显著差异。以下从压测平台的关键需求出发进行对比:

对比维度 React 18 Vue 3 (Composition API)
数据流 单向数据流,状态提升 + Context 响应式代理 (Proxy),双向绑定可选
渲染机制 虚拟 DOM + Fiber 架构,并发模式 虚拟 DOM + 编译时优化 (PatchFlag)
状态管理 Redux / Zustand / Jotai 等第三方 Pinia (官方推荐),Vuex 已退役
TypeScript 支持 原生优秀,社区类型完善 Vue 3 原生支持,但泛型推导略弱
学习曲线 JSX 灵活,Hooks 规则需适应 模板语法直观,Composition API 渐进
生态成熟度 最庞大,第三方库覆盖全面 快速增长,国内社区活跃
压测平台适配性 适合复杂交互、大型仪表盘 适合表单密集、快速原型
选型建议: 若团队以 React 为主,优先选择 React 18 + TypeScript;若团队 Vue 经验更丰富,Vue 3 + Composition API 同样胜任。本课程后续示例以 React 18 展开,但设计思路可平移至 Vue 3。
框架选型决策流程 团队技术栈评估 React 18 + TypeScript Zustand + React Query Vue 3 + Composition API Pinia + Vue Query 统一 API 设计规范

3.2 UI 组件库选择

压测平台包含大量数据表格、表单、图表、拖拽编排等场景,UI 组件库需满足以下要求:

  • 表格组件:支持虚拟滚动、列固定、行展开、批量操作
  • 表单组件:动态表单项、校验联动、JSON Schema 渲染
  • 图表组件:实时折线图、柱状图、热力图(TPS/响应时间/错误率)
  • 拖拽组件:任务节点拖拽编排、DAG 流程图
  • 主题定制:支持暗色模式、品牌色替换
组件库 框架 表格能力 拖拽支持 图表生态 主题定制
Ant Design 5.x React ★★★★★ 需配合 dnd-kit @ant-design/charts CSS-in-JS
Arco Design React / Vue ★★★★☆ 内置拖拽排序 BizCharts Less 变量
Element Plus Vue 3 ★★★★☆ 需配合 vuedraggable ECharts CSS 变量
Naive UI Vue 3 ★★★★☆ 内置拖拽组件 ECharts / 自定义 主题变量
推荐组合: React 技术栈选择 Ant Design 5.x + @ant-design/charts + @dnd-kit/core;Vue 3 技术栈选择 Naive UI + ECharts + vuedraggable@next。

3.3 状态管理方案

压测平台的状态管理需分层处理,避免全局状态膨胀。推荐采用 服务端状态 + 客户端状态 分离策略:

  • 服务端状态:任务列表、压测报告、实时指标 —— 使用 React Query / TanStack Query 或 Vue Query 管理缓存与自动刷新
  • 客户端状态:表单填写、UI 交互状态、拖拽编排 —— 使用 Zustand (React) 或 Pinia (Vue 3)
  • URL 状态:筛选条件、分页页码、Tab 切换 —— 使用 React Router / Vue Router 的 query 参数
状态管理分层架构 服务端状态层 (Server State) React Query / Vue Query · 自动缓存 · 后台刷新 · 乐观更新 客户端状态层 (Client State) Zustand / Pinia · 表单数据 · UI 开关 · 拖拽编排 URL 状态层 (URL State) React Router / Vue Router · 分页 · 筛选 · Tab 切换

3.4 状态管理代码示例

以 React + Zustand 为例,展示压测任务编排的状态管理核心代码:

// store/taskStore.ts
import { create } from 'zustand';
import { devtools, persist } from 'zustand/middleware';

interface TaskNode {
  id: string;
  type: 'http' | 'grpc' | 'websocket' | 'wait';
  label: string;
  config: Record<string, any>;
}

interface TaskEdge {
  source: string;
  target: string;
  condition?: string;
}

interface TaskStore {
  nodes: TaskNode[];
  edges: TaskEdge[];
  selectedNodeId: string | null;
  
  // 操作
  addNode: (node: TaskNode) => void;
  removeNode: (id: string) => void;
  updateNodeConfig: (id: string, config: Record<string, any>) => void;
  setSelectedNode: (id: string | null) => void;
  addEdge: (edge: TaskEdge) => void;
  removeEdge: (source: string, target: string) => void;
}

export const useTaskStore = create<TaskStore>()(
  devtools(
    persist(
      (set) => ({
        nodes: [],
        edges: [],
        selectedNodeId: null,
        
        addNode: (node) =>
          set((state) => ({ nodes: [...state.nodes, node] })),
        
        removeNode: (id) =>
          set((state) => ({
            nodes: state.nodes.filter((n) => n.id !== id),
            edges: state.edges.filter(
              (e) => e.source !== id && e.target !== id
            ),
          })),
        
        updateNodeConfig: (id, config) =>
          set((state) => ({
            nodes: state.nodes.map((n) =>
              n.id === id ? { ...n, config: { ...n.config, ...config } } : n
            ),
          })),
        
        setSelectedNode: (id) => set({ selectedNodeId: id }),
        
        addEdge: (edge) =>
          set((state) => ({ edges: [...state.edges, edge] })),
        
        removeEdge: (source, target) =>
          set((state) => ({
            edges: state.edges.filter(
              (e) => !(e.source === source && e.target === target)
            ),
          })),
      }),
      {
        name: 'task-editor-storage',
        partialize: (state) => ({
          nodes: state.nodes,
          edges: state.edges,
        }),
      }
    )
  )
);
避坑提示: 不要将所有状态放入全局 Store。实时压测指标(TPS、P99 延迟)应通过 WebSocket 推送直接更新图表组件,避免经过全局状态管理造成不必要的重渲染。推荐使用 React Query 的 useQuery 配合 WebSocket 订阅,或使用 Zustand 的 subscribeWithSelector 进行细粒度更新。

3.5 选型总结

层级 React 技术栈 Vue 3 技术栈
框架 React 18 + TypeScript Vue 3 + TypeScript
UI 组件库 Ant Design 5.x Naive UI
图表 @ant-design/charts (G2Plot) ECharts 5
服务端状态 TanStack Query (React Query) TanStack Query (Vue Query)
客户端状态 Zustand Pinia
拖拽编排 @dnd-kit/core + @dnd-kit/sortable vuedraggable@next
路由 React Router 6 Vue Router 4