一、hooks是什么?
no no no,此hook非彼hook!
定义:hook是指在一定时机执行某些操作的方法。婴儿刚出生时会哇哇大哭,肚子饿的时候会咕咕叫,人在难过的时候会伤心流泪等等,这是都是在一些特定的时间点会发生的动作。把这些在特定时间点会发生的动作抽象成一个方法,这个方法就叫做hook。
vue、react、angular等均有自己特定的hooks。以vue来说,其hooks有:beforeCreate、created、beforeMount、mounted、beforeDestory、destroy等,代表组件在其生命周期每个关键节点会执行的方法。
二、为什么要hooks?
通过hooks,开发者可以在组件生命周期各个时间节点注入自己的逻辑,让组件按照自己想要的状态运行。
三、怎么使用hooks?
1、框架本身hooks
对于hooks的使用,不同情况下使用不尽相同。
对于vue而言,vue2直接通过配置化的方式使用hooks,如:
<script>
new Vue({
data() {},
methods: {},
// 组件挂在前会执行的hook
beforeMount() {},
// 组件挂在后执行的hook
mounted() {},
// 组件实例创建前的hook
beforeCreate() {},
// 组件实例创建后执行的hook
created() {},
});
</script>
vue3则需要在引入hooks后再使用,如:
<script setup>
// 引入onMounted、onUnmounted hook
import { ref, onMounted, onUnmounted } from 'vue'
const x = ref(0)
const y = ref(0)
function update(event) {
x.value = event.pageX
y.value = event.pageY
}
onMounted(() => window.addEventListener('mousemove', update))
onUnmounted(() => window.removeEventListener('mousemove', update))
</script>
<template>Mouse position is at: {{ x }}, {{ y }}</template>
2、自定义hooks
某些情况下,我们发现框架本身提供的hooks无法满足我们的需求,那么我们就需要自定义hooks。
以react框架而言,其本身包含的hooks有:useState、useEffect、useRef、useCallback、useMemo等。基于这些hooks,我们可以封装出符合特定场景下使用的hooks。当然,互联网行业巨头阿里已经帮我们完成了这件事,他们已经封装出了一套高质量的hooks——ahooks。这套hooks能涵盖我们日常开发的大多数场景。
已经有轮子了,我们无需再重复早轮子,但是,明白轮子的内部是如何运行的,这确是很重要的。因此,我拿出其中两个hooks加以剖析,来理解下其内部的运行原理。
useLatest
作用:获取变量最新值
适用场景:发生闭包的情况下,由于闭包内的变量不是最新值,因此会出现更新state后,闭包内获取的state不是最新值得情况,因此需要useLatest获取最新值
实现:
import { useRef } from 'react';
const useLatest = value => {
const ref = useRef(value);
ref.current = value;
return ref;
};
export default useLatest;
useSetstate
作用:设置并合并state,设置最新值,合并上一次没有修改的值
实现:
import { useCallback, useState } from 'react';
const isFunction = value => Object.prototype.toString.call(value) === '[function Function]';
/**
* 设置并合并state,设置最新值,合并上一次没有修改的值
* 传入参数:initialState | (() => s)
* 返回参数:[state, setMergeState]
*/
const useSetState = initialState => {
const [state, setState] = useState(initialState);
const mergeState = useCallback(patch => {
setState(preState => {
const newState = isFunction(patch) ? patch(preState) : patch;
return newState ? { ...preState, ...newState } : preState;
});
}, []);
return [state, mergeState];
};
export default useSetState;