Composition API 是 vue3.0 新推出的一种逻辑复用方案,官网是这么说的
用组件的选项 (data、computed、methods、watch) 组织逻辑在大多数情况下都有效。然而,当我们的组件变得更大时,逻辑关注点的列表也会增长。这可能会导致组件难以阅读和理解,尤其是对于那些一开始就没有编写这些组件的人来说。这种碎片化使得理解和维护复杂组件变得困难。选项的分离掩盖了潜在的逻辑问题。此外,在处理单个逻辑关注点时,我们必须不断地“跳转”相关代码的选项块。如果我们能够将与同一个逻辑关注点相关的代码配置在一起会更好。而这正是 Composition API 使我们能够做到的。
想要充分理解这段话,我们首先要知道 vue 模板语法存在的问题
先写个简单的 demo
// simple.vue export default { props: ['id'], data() { return { list: [] }; }, created() { this.getList(this.id); }, watch: { id(newId) { this.getList(newId); } }, methods: { getList(id) { this.$api.post('url', id).then(res => { this.list = res.list; }); } } };
可以看出,创建组件时接受一个 id 去请求 list 数据,当 id 变更时重新发起请求。很常见的业务逻辑,但这种写法导致的问题已经出现,我们想要将此逻辑优雅地进行复用已不可能,因为此逻辑已经和组件本身的选项耦合在了一起。
在此之前,vue 的解决方案是使用 mixins,我们可以将此逻辑抽象为一个对象去混入到别的组件之中,就像这样
// complex.vue let simple = {......}; export default { mixins: [simple] };
似乎还是很简洁不是吗,可是一个组件可能存在着很多逻辑复用的场景,那么你的组件就会变成这样
// complex.vue import simple from './simple.js'; import simple2 from './simple2.js'; import simple3 from './simple3.js'; export default { mixins: [simple, simple2, simple3] };
mixins 可以很好地保障逻辑的复用,不会写任何多余重复的代码,但其弊端是会导致数据的流向变得难以追踪,通俗地讲就是加大了你对于此种代码的理解难度。
作为一名维护者,第一次接触到 complex 这个组件时,你不仅要把 complex 的代码阅读一遍,还要把 simple 、simple2、simple3 的代码通读一遍,不然一不小心,就会触及到以往的功能,而原因仅仅是你定义了一个重复名称的变量 —— minxins 在合并时发生冲突,是以组件自身的数据优先的,而这完全属于意料外的问题。我只想加个简单的小功能,我并不关注这个组件本身复用了多少别的业务逻辑。
到这里,再回过头看看开头给出的官网的话,是不是有了更深的理解呢。
而以我对于 vue 的理解,作者将 html、js、css 融入到一个组件之中,固定地采用一系列选项,就是想为开发者屏蔽掉很多考虑和负担,这也大大加强了我们开发及维护时的便利性,而 mixins 很明显与这一理念冲突,这也就能理解作者当初试图弃用模板语法时的心态了,我们现在有了更好的解决方案 —— Composition API。
还是这个 demo,我们用新的语法去改写
// simple.js import { ref, watchEffect } from 'vue'; export default function simple(id) { let list = ref([]); const getList = id => { this.$api.post('url', id).then(res => { list.value = res.list; }); }; watchEffect(() => { getList(id.value); }); return { list }; }
此时 simple 已经是一个函数了,所以我们在 complex 组件中应该这样引入
// complex.vue import simple from './simple.js'; export default { props: ['id'], setup(props) { let { list } = simple(props.id); return { list }; } };
基于 vue3.0 给出的新语法,list 已通过 ref 变成响应式的数据,而 watchEffect 又帮助我们观测传入的 props.id。当 props 传入的 id 发生变动时,则会触发 simple 里的 getList 方法,产生 list 数据的更新, 再由 complex 组件重新渲染页面,十分清晰明了,也正如官网所说,逻辑关注点相同的代码将很容易配置在一起。
而且有再多的逻辑复用也不怕,因为我们此时已将 mixins 语法 以函数的形式取代掉了,变量名称冲突的问题将迎刃而解,也顺带解决了 mixins 导致的数据流向不清晰的问题,组件的数据来源,一目了然。
// complex.vue import simple from './simple.js'; import simple2 from './simple2.js'; import simple3 from './simple3.js'; export default { setup(props) { let { list } = simple(props); let { list2 } = simple2(props); let { list3 } = simple3(props); return { list, list2, list3 }; } };
以上就是本人对于 Composition API 的一些理解,若有新的心得体会,我会继续补充。