Vue3中提出的一个新概念, 作用: 聚合代码 & 逻辑重用
Vue的组件化做的相当出色, 帮助我们更好的拆分代码和约束代码, 增加可读性, 但是2.x有几个问题也是开发者们时刻在关注的
-
代码逻辑不够聚合, 比较分散, 如果我们的组件代码量一多, 找相同的代码逻辑会显得比较困难
上面的图我把相同逻辑代码用同样的颜色框在了一起, 抛出方法本身的调用以外, 我们依旧可以很清晰的发现这些逻辑是分散的, 非聚合的, 跟react不同, vue只能拆分功能组件却很难拆分逻辑, 所以当我们逻辑一多, 一个组件里存在十多个方法十多种状态, 四五六七八种逻辑的话框会更加多, 找寻起来会比较麻烦, 特别是这个组件不是你自己写的情况下, 在找寻不同逻辑代码会比较困难
-
逻辑重用困难, 我们知道在vue中逻辑和模板是强绑定的状态, 也就是说如果你想要复用一段逻辑, 你必须复用这个组件, 这对拆分关注点又是一种伤害, 有的时候我并不是很想要UI, 只想要这段逻辑, 这就很难处理了, 而vue2中只给我们提供了mixin来混入逻辑, 但是mixin的致命缺陷就是让你更难屡清楚逻辑, 毕竟人家的语法一句话就搞定, 发生了什么你都不知道, 可读性非常的差
我本人曾经就有在表单中多个地方使用mixin的场景, 因为每个表格显示的东西和数据结构都不太一样, 但是最后的操作增删改查和分页操作逻辑都一样, 所以必须使用mixin, 然后导致到后期代码比较难理解, 特别是交给同事的时候, 他们是很难一瞬间清晰的去理清楚这些逻辑的, 顺带一提对于react来说由于hoc和hook, renderprops的存在这些都不是问题,所以这算是vue的弊端了
-
vue的侵入性太强, 导致对typescript这类高阶技术的用法不够自然
基于上面的种种问题, vue推出了composition api的概念
composition api(组合式api)本质上就是vue抽离了一系列方法可以供我们自由引入组合使用, 这里抛出一个问题
在不改变vue模板语法的情况下, vue提供了一个新的函数书写在模板的script
标签中, 该函数名叫做 setup
不讨论具体的文档, 我们直接用composition api来写一个小demo, 该case分别用vue2和vue3咱们都来一次对比一下, 来看看vue3到底是怎么处理之前我提到的三个问题的
需求: 计数器组件
vue2的写法如下
// Count.vue
<template>
<div class="composition-test">
{{ count }}
<button @click="inc">+</button>
</div>
</template>
<script>
export default {
data() {
return {
count: 0
}
},
methods: {
inc() {
this.count ++;
}
}
}
</script>
<style>
</style>
vue3使用composition api如下
// useCount.ts
import { ref } from 'vue'
/**
* 你可能不太明白ref是干嘛的, 他并不是vue2中的获取真实dom引用那么简单,
* 如上方这样引入的ref叫做响应式api, 我们如果想实现vue的响应式功能,
* 在vue2中我们直接写在data中就好了, 然后视图和数据就会产生映射,
* 而在vue3的composition api中我们想要达到映射的效果必须手动调用vue给我们提供的响应式api才可以达到目的,
* 这也很正常, 相较于那些魔法(你不知道怎么的就成为响应式了), 这种显示的转换让人更加的清晰和放心
*/
export default function useCount(defaultValue: number ):[any, Function] {
let count = ref(defaultValue || 0);
function inc() {
return count.value++;
}
return [count, inc]
}
// Count.vue
<template>
<div class="composition-test">
{{ count }}
<button @click="inc">+</button>
</div>
</template>
<script lang="ts">
/*eslint-disable*/
import { ref } from 'vue';
import useCount from '../hooks/useCount';
export default {
setup( props, context ) {
const [count, setCount] = useCount();
return {
count,
setCount
}
}
}
</script>
<style>
</style>
将两组写法进行对比, 我们发现vue3好像可以单独将同一逻辑的状态和方法都抽离出去聚合成一个js文件( 比如count和inc都是跟计数器相关的逻辑 ), 这使得单个Vue文件如果代码量一多, 我们是不是可以做到更好的拆分成一个一个的js文件, 然后在vue组件里导入并且可以一目了然的知道我们当前用到了哪些逻辑, 根据逻辑去追溯相关的状态和方法, 代码逻辑一旦不分散, 就好维护的多
同时你要知道, composition api的写法帮助你把视图和逻辑完全分离, 这意味着你可以不用引入这个组件也可以用到count及其派生方法, 完全更加直观的实现了mixin的功能
当composition api你基本了解以后, 我们来写个伪代码来看看他恐怖的逻辑抽离性
vue2
...
<script>
export default {
data() {
count: 0,
goods: [],
userInfo: {},
isVip: false
}
methods: {
fetchData() {
...
},
clickHandler() {
...
}
setCount() {
...
},
setGoods() {
...
},
setUserInfo() {
...
},
setIsVip() {
...
}
}
}
</script>
...
Vue3
...
<script>
import {onMounted} from 'vue';
import useCount from '../hooks/useCount';
import useGoods from '../hooks/useGoods';
import useUserInfo from '../hooks/useUserInfo';
import useIsVip from '../hooks/useIsVip';
import fetchData from '../fetchData';
export default {
setup() {
// 既然useCount是一个函数, 我们可以给他传递参数来更灵活处理数据
const [count, setCount] = useCount(0);
const [goods, setGoods] = useGoods([]);
const [userInfo, setUserInfo] = useUserInfo({});
const [isVip, setIsVip] = useIsVip(false);
onMounted() {
fetchData();
}
// 除去上方强依赖状态的方法, 其他方法都可以写到最下面
handlerClick = () {
..
}
return {
count, setCount,
goods, setGoods,
userInfo, setUserInfo
isVip, setIsVip,
handlerClick
}
},
}
</script>
...
确实跟react越来越像了, 但是人确实要拥抱变化不是吗? 而是人家也没有强制你用setup, 你想用options方式来定义data, methods都随便你, vue3只是提供了一个新的方式来书写代码, react的hook确实是大型项目中开发的优势, vue这么做我个人认为是非常nice的