本文正在参加「金石计划」
写在最前面
hook
到底是什么?我第一次看到这个词的时候是在学Vue的生命周期,我记得当时上面的翻译是钩子
,好像也还挺形象的,比如create()
–这是页面创建时的钩子函数,mounted()
–这是页面挂载时候的钩子函数…… 当时也没有想那么多,简单形象的理解就是当页面到了某个阶段就会触发某个定义好的钩子函数,也就是到了这个阶段就会被钩子函数钩住,然后执行钩子函数中的代码。
后来学习了Vue3,学习了React的,发现hook
这个单词,它总是出现在我的视野里,但我感觉总不能很好的描述他,他到底是一个什么东西,为什么有那么多人推崇他?为什么以前Vue2的时候很少听到这个单词?它还是我一开始理解的那个钩子
么?
hook是一个函数
如果让你写一个监听鼠标的事件,返回鼠标的坐标的函数你会怎么写?
<script>
let x = 0
let y = 0
function updateMouse(e) {
x = e.pageX
y = e.pageY
console.log(x, y);
}
window.onload = function () {
window.addEventListener("mousemove", updateMouse)
}
window.onunload = function () {
window.removeEventListener("mousemove", updateMouse)
}
</script>
如果让你使用Vue中的选项式API,写出上面的代码会是什么样?
<script>
export default {
name: 'test',
data() {
return {
x: 0,
y: 0
};
},
mounted() {
window.addEventListener("mousemove", this.updateMouse)
},
destroyed() {
window.removeEventListener("mousemove", this.updateMouse)
}
methods: {
updateMouse(e) {
x = e.pageX
y = e.pageY
console.log(x, y);
}
},
};
</script>
ok,每段代码放到它应该待的地方,这对于新手来说确实能很好的理解。此时如果我有很多的组件或者页面都会用到上面这一套获取坐标的逻辑,让你使用mixin的方式,就会变成这样;
// MousePositionMix.js
export default {
data() {
return {
x: 0,
y: 0
};
},
mounted() {
window.addEventListener("mousemove", this.updateMouse)
},
destroyed() {
window.removeEventListener("mousemove", this.updateMouse)
}
methods: {
updateMouse(e) {
x = e.pageX
y = e.pageY
console.log(x, y);
}
},
};
使用的时候,我们只需要引入上面的这个对象
(注意这个用词哈),然后使用mixins
选项即可;
<!--使用到mixin的组件内-->
<script>
import MousePositionMix from '@/mixin/MousePositionMix'
export default {
mixins: [MousePositionMix],
}
</script>
就这样,我们使用了mixin完成了复用和封装,mixin会把我们写的那个对象中的代码,合并到对应的选项中,看起来是相当方面,当然这是你自己刚写的代码,你很清楚,你在页面中使用x
和y
来自哪里,你也很清楚使用的组件中不要写minxin
中包含的data
和methods
,因为这样会覆盖mixin
中的代码。可是时间一长,或者这是别人写的代码,你去接手别人的代码,或者这个组件中有好几个mixin
,此时我希望你仍然面对微笑,仍然知道数据来自哪个mixin,data
和methods
是否依旧唯一,很显然,我们是不知道的,这将是难以维护的,奔溃滴~
一直到Vue3诞生了,此时我邀请你用Vue3的Composition Api
来重新完成以下上面的代码逻辑.
<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
const x = ref(0)
const y = ref(0)
const updateMouse = (e) => {
x.value = e.pageX
y.value = e.pageY
}
onMounted(() => {
window.addEventListener('mousemove', updateMouse)
})
onUnmounted(() => {
window.removeEventListener('mousemove', updateMouse)
})
</script>
和在Vue2中一样,我也想上面的逻辑的得到复用,但是Vue3中已经没有mixin
了,此时我们应该怎么做呢?
import { ref, onMounted, onUnmounted } from 'vue'
export function useMousePosition() {
const x = ref(0)
const y = ref(0)
const updateMouse = (e) => {
x.value = e.pageX
y.value = e.pageY
}
onMounted(() => {
window.addEventListener('mousemove', updateMouse)
})
onUnmounted(() => {
window.removeEventListener('mousemove', updateMouse)
})
return { x, y }
}
我们将这一套逻辑单独写在一个函数中,当我们使用这个函数的时候,就可以返回我们所需要的x
和y
<script setup>
import { useMousePosition } from '@/hooks/test'
const { x, y } = useMousePosition()
</script>
此时有人就会说了:哇,就这么简单么?这也太好用了吧。也有人会说,额,这不就是封装了一个通用的函数么,哇什么哇,大惊小怪的。确实你这么说也没错,但是这是Vue2所不具备的,如果没有composition-api,则不具备这一项能力,有了组合式api我们可以在函数中可以使用Vue的响应式特性、Vue的生命周期等等,通过Hooks写法能将原来分散在各个选项中的代码,聚合到一起。如图:
不得不提一嘴React
我个人也学习过一些React的相关知识。也明白hook这一代码组合机制是有React提出来的。
在之前的React版本中,好像是16.8版本之前,React的写法都是类式组件,函数式组件是没有自己的state,只是适用于简单的组件,做一些接收参数展示。直到后面出现了hook,它实现了可以在函数中使用state及React的其他特性。同时我们也可以自定义hook去更好的复用组件逻辑,约定以use开头。
很显然,这个hook
它好像不再是我一开理解的那个钩子
的意思,不是系统运行到某一时期时,会调用被注册到该时机的回调函数了。也就是说至react16.8之后,hook有了一些特殊的含义。它变成了一种使函数式组件具备更强开发能力的方法,能在函数式组件中完成生命周期、状态管理、逻辑复用等工作能力。
总结
hook是一个函数,是一种代码组合机制,使你在无需修改组件结构的情况下复用状态逻辑(函数可以复用逻辑代码,但是没办法复用带状态的逻辑代码,这一点要理解)。
函数有的优点,比如代码复用、描述性质、代码封闭性等等,hook都有,除此之外hook可以让你更好的实现复用,清晰的知道数据的来源,方法和属性好追溯;
原文链接:https://juejin.cn/post/7215881683295682617 作者:白水清风