截至目前,组合式函数应该是在VUE 3应用程序中组织业务逻辑最佳的方法。它让我们可以把一些小块的通用逻辑进行抽离、复用,使我们的代码更易于编写、阅读和维护。
根据官方文档说明,在 Vue 应用的概念中,“组合式函数”是一个利用 Vue 组合式 API 来封装和复用有状态逻辑的函数。
这就意味着,任何有状态逻辑,并且使用了响应式处理的逻辑都可以转换成组合式函数。这和我们平时抽离封装的公共方法还是有一些区别的。我们封装的公共方法往往是无状态的:它在接收一些输入后立刻返回所期望的输出。而组合式函数往往是和状态逻辑关联的。简单的理解就是“**可复用逻辑的集合,专注点分点**”
结论:就是为了让Compoosition Api
更好用更丰满,让写Vue3更畅快! 其实这个问题更深意义是为什么Vue3比Vue2更好!无外呼性能大幅度提升,其实编码体验也是Vue3的优点**Composition Api
的引入(解决Option Api在代码量大的情况下的强耦合)** 让开发者有更好的开发体验。
以函数形式抽离一些可复用的方法像钩子一样挂着,随时可以引入和调用,实现高内聚低耦合的目标;
const {nameRef,Fn} = useXX()
(在setup函数解构出自定义hooks的变量和方法)
简单的加减法计算,将加法和减法抽离为2个自定义Hooks,并且相互传递响应式数据
import { ref, watch } from 'vue';
const useAdd= ({ num1, num2 }) =>{
const addNum = ref(0)
watch([num1, num2], ([num1, num2]) => {
addFn(num1, num2)
})
const addFn = (num1, num2) => {
addNum.value = num1 + num2
}
return {
addNum,
addFn
}
}
export default useAdd
import { ref, watch } from 'vue';
export function useSub ({ num1, num2 }){
const subNum = ref(0)
watch([num1, num2], ([num1, num2]) => {
subFn(num1, num2)
})
const subFn = (num1, num2) => {
subNum.value = num1 - num2
}
return {
subNum,
subFn
}
}
num1:
num2:
加法等于:{{ addNum }}
减法等于:{{ subNum }}
3. 自定义Hooks 还可以传参
接上面的例子
平均功能-Hook
import { ref, watch } from "vue";
export function useAverage(addNum) {
const averageNum = ref(0);
watch(addNum, (addNum) => {
averageFn(addNum);
});
const averageFn = (addNum) => {
averageNum.value = addNum / 2;
};
return {
averageNum,
averageFn,
};
}
组件内:
//加法功能-自定义Hook(将响应式变量或者方法形式暴露出来)
const { addNum, addFn } = useAdd({ num1, num2 })
addFn(num1.value, num2.value)//主动调用,返回最新addNum
//平均功能-自定义Hook- hook传入参数值来其他hook暴露出来的变量
const { averageNum, averageFn} = useAverage(addNum)
averageFn(addNum.value)
Mixin不足
在 Vue 2 中,mixin 是将部分组件逻辑抽象成可重用块的主要工具。但是,他们有几个问题:
1、Mixin 很容易发生冲突:因为每个 mixin 的 property 都被合并到同一个组件中,所以为了避免 property 名冲突,你仍然需要了解其他每个特性。
2、可重用性是有限的:我们不能向 mixin 传递任何参数来改变它的逻辑,这降低了它们在抽象逻辑方面的灵活性。
//minxins.js 文件
export default{
data(){
return{
message:'混入对象',
name:'zhangsan000'
}
},
methods: {
logMessage() {
console.log('打印message', this.message);
}
}
}
组件:
// 使用
import minxins from "./common/minxins";
import minxins1 from "./common/minxins1"; // 举例
import minxins2 from "./common/minxins2"; // 举例
export default{
mixins: [minxins, minxins1, minxins2], //可混入多个文件
data(){
return{
message:'混入对象新的',
bar:'bar',
}
},
created(){
this.logMessage(); // 打印 '混入对象新的'
console.log('created组件钩子被调用')
},
上面的代码 可以看出: mixins 的深度合并非常隐式,让代码逻辑更难理解和调试,具体表现为如下几点:
Vue3自定义Hooks, 引用时将响应式变量或者方法显式暴露出来如:
const {nameRef,Fn} = useXX()
export default {
mixins: [ addMixin, subMixin], //组件内混入加法和减法Mixin
mounted(){
this.add(num1,num2) //调用加法addMixin内部的add方法
this.sub(num1,num2) //调用减法subMixin内部的sub方法
}
}
如果this.add(num1,num2)
和 this.sub(num1,num2)
计算的结果返回的同名变量totalNum,由于JS单线程,后面引入的会覆盖前面的,totalNum最终是减法sub的值
如上面例子
//加法功能-自定义Hook(将响应式变量或者方法形式暴露出来)
const { addNum, addFn } = useAdd({ num1, num2 })
addFn(num1.value, num2.value)
//减法功能-自定义Hook (将响应式变量或者方法形式暴露出来)
const { subNum, subFn } = useSub({ num1, num2 })
subFn(num1.value, num2.value)
在Vue3自定义Hooks中,虽然加法和减法Hooks都返回了totalNum,但是利用ES6对象解构很轻松给变量重命名
//useHello.js
import { ref } from 'vue';
export function useHello() {
let message = ref('组合函数api');
const logMessage = (val) => {
console.log(val + message.value);
};
return { message, logMessage };
}
组件使用时
{{ message }}
上面代码可以看出:
Vue2时代Option Api ,data、methos、watch.....
分开写,这种是碎片化的分散的,代码一多就容易高耦合,维护时来回切换代码是繁琐的!
Vue3时代Composition Api
,通过利用各种Hooks和自定义Hooks将碎片化的响应式变量和方法按功能分块写,实现高内聚低耦合
形象的讲法:Vue3自定义Hooks是组件下的函数作用域的,而Vue2时代的Mixins是组件下的全局作用域。全局作用域有时候是不可控的,就像var和let这些变量声明关键字一样,const和let是var的修正。Composition Api正是对Vue2时代Option Api 高耦合和随处可见this的黑盒的修正,Vue3自定义Hooks是一种进步。
把Mixin和自定义Hook进行比较,一个是Option Api的体现,一个是Composition Api的体现。如果能理解高内聚低耦合的思想,那么就能理解为什么Vue3是使用Composition Api,并通过各种自定义Hooks使代码更强壮。
以使用可组合的函数式,同时获得ref和reactive的好处
import { ref,reactive}from 'vue'
function useMouse(){
return {
x:ref(0),
y:ref(0),
}
}
const {x} = useMouse()
const mouse = reactive(useMouse())
mouse.x === x.value //true
1.可以直接使用es6解构其中的Ref使用
2.根据使用方式,当想要自动解包的功能时,可以使用 reactive将其转换为对象
使用组合式API,我们甚至可以将异步操作转换为“同步”的
异步
const data = await fetch('https://196.198.1.0/use/').then(r=>r.json())
// use data
组合式api
const {data} = await useFetch('https://196.198.1.0/use/').json()
const user_url = computed(()=>data.value?data.value.user_url:'')
先建立数据间的“连结”,然后再等待异步请求返回将数据填充。概念和react 中的SWR(stale-while-revalidate)类似。
由于组合式API天然提供的灵活性,状态可以独立于组件被创建并使用
但是不兼容ssr(服务器渲染)
使用provide和inject 来共享应用层面的状态。
vue3中的自定义hook函数