说实话,学Vue 3.5的过程中,我有好几次想放弃。

我是一个后端开发,平时也写一些前端,但主要是jQuery和Vue 2的水平。最近项目需要,我开始学Vue 3.5,想着不就是个前端框架嘛,应该不难。结果,学了一个月,被各种新概念、新语法、新坑搞得头大,好几次差点放弃。

这篇文章,我想分享一下我学习Vue 3.5的经历,聊聊那些让我想放弃的瞬间,以及最后是怎么坚持下来的。希望能给同样在学Vue 3的朋友一些参考。

入门:看起来很简单

刚开始学Vue 3的时候,觉得很简单。

官方文档写得很好,教程一步步带你做一个Todo List。创建组件、绑定数据、处理事件,看起来和Vue 2差不多,只是语法稍微变了一下。

我跟着教程,很快就做出了一个简单的Todo List,增删改查都有。那时候我觉得,Vue 3也不过如此嘛,一周就能上手。

但很快,我就发现自己太天真了。

第一个坎:Options API还是Composition API

第一个让我困惑的,是Options API和Composition API的选择。

Vue 3同时支持两种写法:Options API和Vue 2差不多,data、methods、computed、watch,分块写;Composition API是新的写法,所有逻辑都写在setup函数里,用ref、reactive、computed这些函数。

官方推荐用Composition API,说它更好地支持逻辑复用、更好的TypeScript支持、更好的代码组织。但我看了很多教程和项目,发现很多人还在用Options API,而且网上的资料两种写法都有,混在一起。

我一开始学的是Composition API,但写着写着就发现,逻辑都堆在setup里,代码长了之后很乱。而且,ref和reactive怎么选?什么时候用ref,什么时候用reactive?computed和watch有什么区别?这些问题,官方文档讲得不够清楚,我看了很多文章还是一知半解。

后来我才明白,Composition API不是把所有东西都堆在setup里,而是要按逻辑关注点组织代码。一个功能相关的ref、computed、method,放在一起,甚至抽成一个自定义Hook(composable)。这样代码才清晰。

但这个理解,是我踩了很多坑、写了很多烂代码之后才有的。刚开始的时候,真的是一脸懵。

第二个坎:响应式系统的各种坑

Vue 3的响应式系统,比Vue 2强大了很多,但也复杂了很多,坑也更多。

我遇到的第一个坑是,ref和reactive的区别。

ref可以包装基本类型和对象,访问的时候要加.value。reactive只能包装对象,访问的时候不用加.value,但解构之后会失去响应式。

我一开始搞不清楚,一会儿用ref,一会儿用reactive,经常忘记加.value,或者解构reactive对象之后发现数据不更新了。调试了半天才发现,是响应式丢了。

后来我总结了一个简单的规则:基本类型用ref,对象用reactive。但reactive对象不要解构,要解构就用toRefs。虽然这个规则不完美,但至少能避免大部分坑。

第二个坑是,watch和watchEffect的区别。

watch是监听特定的数据源,数据变化时执行回调。watchEffect是自动追踪依赖,回调里用到的响应式数据变化了,就重新执行。

我一开始用watch,经常忘记设置immediate: true,导致初始化的时候不执行。用watchEffect的时候,又经常因为依赖追踪的问题,导致不该执行的时候执行了,或者该执行的时候没执行。

而且,watch的deep选项也很坑。监听一个对象,如果不设deep: true,对象内部属性变化了不会触发。但设了deep: true,性能又会变差,因为要深度遍历。

第三个坑是,computed的缓存和副作用。

computed是有缓存的,只有依赖变化了才会重新计算。这个设计很好,但如果computed里有副作用(比如修改其他响应式数据、调用API),就会出问题。我一开始在computed里调用API,结果缓存导致API不重新调用,调试了半天。

后来才知道,computed应该是纯函数,只做计算,不做副作用。副作用应该放在watch或者method里。

这些响应式的坑,每一个都让我调试了很久。好几次我都想说,这也太复杂了,不如用回Vue 2。

第三个坎:组件通信的各种方式

Vue 3的组件通信方式,比Vue 2多了很多,也复杂了很多。

父子组件通信,props和emit,这个和Vue 2差不多,还比较好理解。但Vue 3的v-model改了,组件上可以用多个v-model,还有defineProps和defineEmits的语法,一开始也不太习惯。

跨层级通信,Vue 2用provide/inject或者Vuex,Vue 3还是provide/inject,但用法变了,而且还有了Pinia(Vuex的替代品)。

我一开始用provide/inject,发现深层组件拿到数据之后,修改的时候很混乱,不知道是谁改的。后来改用Pinia,发现Pinia确实比Vuex简单好用,state、getters、actions,没有mutations了,直接在actions里改state。但Pinia的setup store写法,又和Composition API一样,需要适应。

还有兄弟组件通信、全局状态管理、事件总线(Vue 3移除了$on/$off,不能用事件总线了),这些都需要重新学习。

最让我头疼的是,一个项目里,不同的人用不同的通信方式,有的用props,有的用provide/inject,有的用Pinia,代码风格不统一,维护起来很痛苦。

后来我们团队定了规范:父子用props/emit,跨层级用Pinia,小型的局部状态用provide/inject。统一了之后,代码才清晰起来。

第四个坎:生命周期和组合式函数

Vue 3的生命周期钩子,在Composition API里,都变成了onXxx的函数,比如onMounted、onUpdated、onUnmounted。而且,这些钩子只能在setup里调用,不能在普通函数里调用。

我一开始在一个普通的工具函数里调用了onMounted,结果报错,调试了半天才发现,生命周期钩子必须在setup的上下文里调用。

还有组合式函数(composable),这是Vue 3推荐的逻辑复用方式。把可复用的逻辑抽成一个函数,比如useMouse、useLocalStorage、useFetch。

我一开始写composable,经常犯几个错误:

第一个错误是,在composable里返回reactive对象,调用方解构之后失去响应式。正确的做法是返回ref,或者用toRefs处理。

第二个错误是,composable里的副作用没有清理。比如,在composable里加了事件监听,组件卸载的时候没有移除,导致内存泄漏。正确的做法是用onUnmounted清理。

第三个错误是,composable的命名不规范。按照约定,composable应该以use开头,比如useMouse、useFetch。我一开始随便命名,后来看了官方的风格指南才改过来。

写composable的过程,其实是一个思维方式的转变:从"组件里写逻辑"变成"逻辑抽成函数,组件里调用"。这个转变,需要时间和练习。

第五个坎:TypeScript的类型体操

Vue 3对TypeScript的支持比Vue 2好很多,但对于不熟悉TypeScript的人来说,类型体操真的很头疼。

我遇到的第一个问题是,props的类型定义。defineProps的泛型写法,一开始怎么都写不对。比如:

const props = defineProps<{
  title: string
  count?: number
  list: string[]
}>()

这个写法看起来简单,但如果props有默认值,还要用withDefaults,又多了一层复杂度。

第二个问题是,ref的类型。ref的类型有时候能自动推断,有时候需要手动指定。比如:

const count = ref(0) // 自动推断为Ref<number>
const user = ref<User | null>(null) // 需要手动指定

第三个问题是,reactive的类型。reactive的类型推断有时候不太直观,尤其是嵌套对象和数组。

第四个问题是,composable的返回值类型。写composable的时候,返回值的类型要定义清楚,否则调用方拿不到正确的类型提示。

这些TypeScript的问题,对于有TS基础的人来说可能不算什么,但对于我这种后端转前端、TS只懂皮毛的人来说,真的是"类型体操",经常为了一个类型报错折腾半天。

好几次我都想说,不用TypeScript了,用JavaScript写多爽。但后来发现,类型虽然麻烦,但能避免很多低级错误,而且IDE的提示太香了,写代码的效率反而提高了。

第六个坎:构建工具和生态的变化

Vue 3的生态,和Vue 2时代也有很大变化。

第一个变化是,Vite替代了Webpack。Vue 3的官方脚手架create-vue,默认用Vite构建。Vite确实快,开发服务器秒启动,热更新也快。但Vite的配置和Webpack不一样,很多插件也不一样,需要重新学习。

第二个变化是,Vue Router和Vuex都升级了。Vue Router 4的写法有一些变化,Vuex变成了Pinia。虽然核心概念没变,但API和最佳实践都变了。

第三个变化是,UI组件库的升级。Element UI变成了Element Plus,Ant Design Vue也升级到了3.x。这些组件库的API和用法,和Vue 2时代有一些差异,需要重新看文档。

第四个变化是,新的工具和库。比如VueUse(一个Vue组合式工具库)、Nuxt 3(Vue的SSR框架)、Volar(Vue 3的VS Code插件,替代了Vetur)。这些新工具,有的很好用,有的增加了学习成本。

生态的变化,意味着Vue 2的经验不能直接复用,很多东西要重新学。对于有经验的Vue 2开发者来说,这种"一切都变了"的感觉,确实容易让人想放弃。

我是怎么坚持下来的

说了这么多"想放弃"的瞬间,最后我还是坚持下来了,而且现在觉得Vue 3确实很好用。

我是怎么坚持下来的呢?

第一个方法是,做一个真实的项目。光看文档、跟着教程做Todo List,是学不会的。我找了一个真实的项目需求,一边做一边学。遇到问题就查文档、搜Google、问AI。做项目的过程中,遇到的问题都是真实的,解决了之后印象也深。

第二个方法是,接受自己的笨拙。刚开始写Vue 3的时候,代码写得很烂,经常犯低级错误。我告诉自己,这是正常的,学新东西都有这个过程。不要因为写得烂就放弃,写着写着就好了。

第三个方法是,建立自己的代码片段库。把常用的模式、composable、组件写法,保存成代码片段。下次用的时候直接拿出来改,不用每次都从头想。这样效率提高了,也减少了犯错。

第四个方法是,和有经验的人交流。我们团队有一个Vue 3用得好的同事,我遇到问题就去问他。他的一句话,有时候比我自己查半天文档还有用。如果身边没有这样的人,可以去社区、论坛、AI助手那里问。

第五个方法是,不要追求一次学完。Vue 3的内容很多,Composition API、响应式、组件通信、Pinia、Vue Router、TypeScript、Vite,不可能一次都学会。先学最核心的,能写项目了,再慢慢深入其他部分。用中学,比学完再用,效率高得多。

现在的感受

学了一个多月Vue 3.5之后,我现在的感受是:真香。

虽然学习曲线比Vue 2陡,坑也多,但一旦上手了,开发体验比Vue 2好很多。

第一个好处是,逻辑复用更方便。Composition API和composable,让逻辑复用变得很自然。比如,表单验证、分页、数据获取,都可以抽成composable,在多个组件里复用。以前Vue 2的mixin,各种命名冲突、来源不清,现在的composable清晰多了。

第二个好处是,代码组织更灵活。按逻辑关注点组织代码,一个功能的所有相关代码(数据、计算、方法、监听)放在一起,而不是分散在data、methods、computed、watch里。代码长了之后,这种组织方式的优势很明显。

第三个好处是,TypeScript支持更好。类型提示更准确,重构更安全。虽然学的时候很痛苦,但用熟了之后,真的离不开类型提示了。

第四个好处是,性能更好。Vue 3的响应式系统用Proxy实现,比Vue 2的Object.defineProperty更强大,性能也更好。编译时优化也让运行时更快。

第五个好处是,生态更现代。Vite、Pinia、VueUse、Nuxt 3,这些新工具让开发体验提升了很多。

所以,虽然过程很痛苦,好几次想放弃,但坚持下来之后,觉得这些痛苦都是值得的。

给初学者的建议

最后,给正在学Vue 3、或者准备学Vue 3的朋友几个建议:

第一,不要被新概念吓到。Composition API、ref、reactive、composable,这些概念听起来很新,但本质上还是那些东西:数据、计算、方法、监听。只是组织方式变了。理解了本质,就不会觉得难了。

第二,先学核心,再学生态。先把Composition API和响应式系统搞懂,能写简单的组件了,再学Pinia、Vue Router、TypeScript。不要一开始就什么都学,容易混乱。

第三,多写项目,少看教程。看十遍教程,不如自己写一个项目。在真实项目中遇到问题、解决问题,是最好的学习方式。

第四,善用官方文档和AI助手。Vue 3的官方文档写得很好,遇到问题先查文档。文档解决不了的,问AI助手,它能给你很详细的解答。

第五,接受不完美。刚开始写的代码肯定不优雅,肯定会犯很多错。没关系,先让代码跑起来,然后再慢慢优化。写代码是一个迭代的过程,不是一次就能写好的。

第六,不要轻易放弃。学新东西都有一个痛苦的过程,挺过去就好了。Vue 3虽然学习曲线陡,但一旦上手,开发体验会比Vue 2好很多。

写在最后

从入门到想放弃,再到真香,这就是我学Vue 3.5的经历。

其实不只是Vue 3,学任何新技术,都会有这样的过程:一开始觉得简单,然后遇到各种坑,想放弃,坚持下来之后,发现确实很好用。

技术在不断进步,新的框架、新的语法、新的工具不断出现。作为开发者,我们要不断学习,才能跟上时代。学习的过程虽然痛苦,但每一次学会新东西,都是一次成长。

希望我的经历能给正在学Vue 3的你一些鼓励和参考。不要放弃,坚持下去,你会发现Vue 3真的很香。