Vue.js 踩坑记:从 React 转型后的真实项目实战

温柔_学者
2025-12-21 10:54
阅读 1451

去年底,我们小厂业务线接到一个“紧急又重要”的任务——重构内部运营后台。作为团队里唯一一个后端(兼半个前端),我原本以为又是套个 Ant Design Pro 交差了事。结果产品经理甩过来一句:“这次要用 Vue3,UI 风格对标 Notion。”我当时就懵了:我可是 Vim 党,连 VS Code 都很少开,更别说天天和 Composition API 打交道了

但没办法,老板说“技术要多元化”,加上隔壁组用 React 写的系统老是内存泄漏,运维半夜打电话骂人,领导一拍脑袋:“试试 Vue 吧,听说更轻量。”


为啥不继续用 React?

说实话,我对 React 并无偏见。之前维护的老系统就是 React + Redux,写得还挺顺手。但问题也明显:

  • Bundle 太大:光 React + ReactDOM 就 120KB+,gzip 后还是比 Vue 大一圈
  • 状态管理复杂:Redux 写起来像在填表格,每个 action 都要定义 type、payload、reducer,改个字段要改五处
  • SSR 配置反人类:上次搞服务端渲染,webpack 配置改到凌晨三点,最后发现是 babel-loader 没加 target: 'node'

而 Vue 的卖点很实在:渐进式、文档友好、单文件组件直观。对我们这种人力紧张的小团队来说,上手快比什么都重要。


实战:从零搭起一个可维护的 Vue3 项目

1. 技术栈选型:别贪多,够用就行

我们最终定了这套组合:

  • 框架:Vue 3.4(Composition API)
  • 构建工具:Vite(告别 webpack 的 30 秒启动)
  • UI 库:Naive UI(TypeScript 支持好,主题定制灵活)
  • 状态管理:Pinia(比 Vuex 简洁太多)
  • 路由:Vue Router 4
  • HTTP 客户端:Axios(虽然 fetch 原生,但拦截器太香)

💡 小厂经验:别一上来就搞微前端、Monorepo。先跑起来,再优化。我们连 Eslint 都是第二周才加的——第一周光赶 deadline 了。

2. 目录结构:让新人三天内能看懂

src/
├── api/              # 接口定义
├── assets/           # 静态资源
├── components/       # 通用组件
├── composables/      # 自定义组合函数(重点!)
├── layouts/          # 布局组件
├── pages/            # 页面级组件
├── router/           # 路由配置
├── stores/           # Pinia store
├── types/            # TS 类型定义
├── utils/            # 工具函数
└── App.vue

关键设计:把 composables 单独拎出来。比如用户权限校验,我写了个 useAuth.ts

// composables/useAuth.ts
import { ref, computed } from 'vue'
import { useUserStore } from '@/stores/user'

export function useAuth() {
  const userStore = useUserstore()
  const hasPermission = computed(() => (perm: string) => {
    return userStore.permissions.includes(perm)
  })

  // 返回响应式引用,模板里直接用
  return { hasPermission }
}

在页面里调用:

<script setup>
import { useAuth } from '@/composables/useAuth'
const { hasPermission } = useAuth()
</script>

<template>
  <button v-if="hasPermission('delete')">删除</button>
</template>

效果:逻辑复用率提升 70%,测试也方便——直接 mock useUserStore 就行。


和 React 的综合对比:不是谁更好,而是谁更适合

我知道肯定有人要问:“Vue 和 React 到底哪个强?”作为两边都踩过坑的人,我的结论很朴素:

维度 Vue 3 React 18
上手速度 ⭐⭐⭐⭐⭐(模板直观) ⭐⭐⭐(JSX 需适应)
状态管理 Pinia 简洁,无需 middleware Redux Toolkit 还行,但配置多
性能 编译时优化,更新更精准 Fiber 可中断,但 diff 成本高
TypeScript 支持 原生支持,类型推导强 需额外配置,泛型容易翻车
生态成熟度 中后台够用,复杂交互略弱 生态无敌,但碎片化严重
团队协作 模板分离,前端/切图更容易介入 全 JS,对非 JS 开发者不友好

🤔 个人吐槽:React 社区总在造新轮子(Zustand、Jotai、Recoil…),Vue 社区相对稳定。对我们这种没时间追新的人,稳定就是生产力。


踩过的坑:那些让我想砸键盘的瞬间

坑 1:响应式丢失 —— ref vs reactive

一开始我把所有状态都用 reactive 包:

const state = reactive({ list: [] })
// 在 API 回调里
state.list = res.data // OK

但后来需要把 list 传给子组件,结果子组件修改无效!因为 reactive 解包后失去响应性。

正确做法:用 ref 包数组/对象,或者在传递时用 toRefs

// 父组件
const list = ref([])
// 子组件 props
defineProps<{ list: Ref<Item[]> }>()

💡 教训:简单数据用 ref,复杂嵌套对象才考虑 reactive。别为了少写 .value 而牺牲可维护性。

坑 2:Vite + Axios 的跨域代理

开发时接口在 http://api.internal.com,本地启 Vite 服务在 localhost:3000,直接请求 CORS 报错。

错误配置(网上抄的):

// vite.config.js
server: {
  proxy: {
    '/api': 'http://api.internal.com'
  }
}

结果请求变成 GET /api/users → 转发到 http://api.internal.com/api/users,但后端路径是 /users

正确配置

server: {
  proxy: {
    '/api': {
      target: 'http://api.internal.com',
      changeOrigin: true,
      rewrite: (path) => path.replace(/^\/api/, '')
    }
  }
}

然后 Axios 基地址设为 /api,完美解决。


性能优化:小厂也要讲究用户体验

虽然只是内部系统,但加载慢了运营小姐姐会骂人。我们做了几件事:

  1. 路由懒加载
    // router/index.ts
    const Dashboard = () => import('@/pages/Dashboard.vue')
    
  2. 图片懒加载:用 IntersectionObserver 自制指令
  3. 列表虚拟滚动:超过 100 条数据就上 vue-virtual-scroller
  4. 缓存计算结果:用 computed 代替方法调用

最惊喜的是 Vite 的 HMR 速度——改一行 CSS,浏览器 50ms 内更新,再也不用等 webpack 的“92% additional asset processing”。


最后:为什么我觉得 Vue 适合小团队?

写这篇文章时,已经是上线后第三个月。系统稳定运行,连测试同学都说“这次 Bug 少多了”。回顾整个过程,Vue 给我的最大感受是:它不炫技,但务实

  • 模板语法让 HTML/CSS 开发者也能参与
  • 单文件组件天然隔离关注点
  • 文档示例即拷即用,不用翻 GitHub issue
  • 生态工具链成熟(Volar、Vue Devtools)

当然,如果是超大型应用或需要极致灵活性(比如做设计器),React 可能更合适。但对我们这种三个人维护五条业务线的小厂来说,Vue 的“约定优于配置”省下了大量沟通和调试成本。


一点私货:后端眼中的前端未来

最近我在业余时间研究 Rust,发现前端和系统编程有个共同趋势:类型安全 + 编译时优化。Vue 3 的 <script setup> + TypeScript,其实就是在往这个方向走——用编译器提前发现问题,而不是靠 runtime 报错。

也许不久后,我们会看到更多像 Svelte、Solid.js 这样“编译时框架”的崛起。但无论如何,工具只是手段,解决问题才是目的

对了,上周产品经理又提了新需求:“能不能加个暗黑模式?”
我笑了笑,打开 naive-ui 的文档,5 分钟搞定。
——这才是小厂程序员的快乐。

📌 彩蛋:如果你也在用 Vim 写 Vue,推荐插件 vim-vue + coc-volar,补全体验接近 IDE。虽然偶尔还是会手滑按成 :wq 关掉浏览器标签页……

评论 0

最热最新
暂无评论
温柔_学者Lv.1
0
影响力
0
文章
0
粉丝