【每日一题】vue Hooks 有哪些?
人生苦短,总需要一点仪式感。比如学前端~
什么是 Hooks
hooks
字面意思就是钩子函数,那么钩子函数的定义是什么呢?
钩子函数
:在一个事件触发的时候,在系统级捕获到了它,然后做一些操作。一段用以处理系统消息的程序。钩子就是在某个阶段给你一个做某些处理操作的机会-----类似回调函数。
钩子函数:
一个函数/方法,在系统消息触发时被系统调用,例如onclick的函数值,当click事件触发的时候,函数会被调用。
不是用户自己触发的,例如发布订阅者模式的方法的实现
钩子函数的名称是确定的,当系统消息触发后,自动会调用
例如Vue的watch()函数,用户只需要编写watch()的函数体里面的函数,当页面元素发生变化的时候,系统就会先调用watch()
例如react的componentWillUpdate函数,用户只需要编写componentWillUpdate的函数体,当组件状态发生改变更新的时候,系统就会调用componentWillComponent
Vue Hooks 就是一些 vue 提供的内置函数,这些函数可以让 Function Component 和 Class Component 一样能够拥有组件状态(state)以及进行副作用(side effect)
为什么使用 Vue Hooks?
首先从 Class-component/Vue-options
开始说起
跨组件代码难以复用
大组件,维护困难,颗粒度不好控制,细粒度划分时,组件嵌套层次太深会影响性能
类组件,this 不可控,逻辑分散,不容易理解
mixins 具有副作用,逻辑互相嵌套,数据来源不明,且不能互相消费
当一个模板依赖很多 mixin 的时候,很容易出现数据来源不清或者命名冲突的问题,而且开发 mixins 的时候,逻辑以及逻辑依赖的属性互相分散且 mixins 之间不可互相消费。这些都是开发中令人痛苦的点,因此 vue3.0 中引入 hooks 相关的特性非常明智
常用的 hooks 讲解
withHooks
const Foo = withHooks((h) => {
// state
const [count, setCount] = useState(0);
// effect
useEffect(() => {
document.title = "count is " + count;
});
return h("div", [
h("span", `count is: ${count}`),
h(
"button",
{
on: {
click: () => setCount(count + 1),
},
},
"+"
),
]);
});
withHooks 是一个高阶函数,传入一个函数,这个函数内部返回一个 vnode,withHooks 方法返回的是一个 vue 的选项对象
Foo = {
created() {},
data() {},
render() {},
};
这个选项对象可以直接调用 Vue.component 方法生成全局组件,或者在 render 方法中生成 vnode
useState
useState 理解起来很简单,和 Class Component 的 vuex 中 state 是一样的,都是用来管理组件状态的。
因为 Function Component 每次执行的时候都会生成新的函数作用域,所以同一组件的不同渲染(render)之间是不能够共用状态的。因此开发者一旦需要在组件中引入状态就需要将原来的 Funtion Component 改为 Class Component,这使得开发者的体验十分不好。
useState 就是用来解决这个问题的,它允许 Function Component 将自己的状态持久化到 vue 运行时的某个地方,这样在组件每次渲染的时候都可以从这个地方拿到该状态,而且当该状态被更新的时候,组件也会重渲染。
//声明
const [count, setcount] = useState(0)
const [state, setState] = useState({
status: 'pending',
data: null,
error: null
})
const handleTextChange(value) => {
setText({
status: 'changed',
data: value,
error: null
})
}
//引用
<div>{count}</div>
< ... onClick= setcount(count + 1) ... >
<div>{state}</div>
onChange=handleTextChange(count)
useState 接收一个 initial 变量作为状态的初始值,返回值是一个数组。
返回数组的第一个元素代表当前 state 的最新值 第二个元素是一个用来更新 state 的函数。
这里要注意的是 state 和 setState 这两个变量的命名不是固定的,应该根据你业务的实际情况选择不同的名字,可以是 setA 或 setB,需要注意的是 setState 这个是全量替代
我们在实际开发中,一个组件可能不止一个 state,如果组件有多个 state,则在组件内部多次调用 useState,这些使用类似 Vuex 里面的 state 的使用方式
useEffect
useEffect 用于添加组件状态更新后,需要执行的副作用逻辑
// 语法
useEffect(() => {}, deps)
useEffect 指定的副作用逻辑,也就是其第一个参数(回调函数)的执行逻辑如下:
会在组件挂载后执行一次 在每次组件渲染后根据指定的依赖有选择地执行 并在组件卸载时执行清理事件的逻辑
第二个参数 (deps)表示依赖项,若deps内的数据发生变化,则执行回调函数
import { withHooks, useState, useEffect } from "vue-hooks";
const Foo = withHooks((h) => {
const [count, setCount] = useState(0);
useEffect(() => {
document.title = "count is " + count;
});
return h("div", [
h("span", `count is: ${count}`),
h("button", { on: { click: () => setCount(count + 1) } }, "+"),
]);
});
代码中,通过 useEffect 时,每当 count 的状态值发生变化时,都会重置 document.title。
这里没有指定 useEffect 的第二个参数 deps,表示只要组件重新渲染都会执行 useEffect 指定的逻辑,不限制必须是 count 变化时
useRef
useRef 是用来在组件不同渲染之间共用的一些数据的,它的作用和我们在 Vue Class Component 里面为$refs.xxx 赋值是一样的。那么它的一些特性就跟 refs 是类似:
组件更新之后,可以获取最新的状态、值 值不需要响应式处理 独立于其他作用域之外,不污染其他作用域
useRef 返回的是对象,对象有一个current
属性表示当前最新的状态、值
const [count, setcount] = useState(0);
const num = useRef(count);
const addCount = () => {
let sum = count++;
setcount(sum);
num.current = sum;
console.log(count, num.current);
};
//得到的结果是
// 0 1
// 1 2
// 2 3
// ...
useData
useData 可以理解为 Vue Class Funtion 里面的$data
也可以认为与 useState 类似。不同的是:它没有提供更新器,对外返回的数据发生变化时,有可能会丢失响应式监听。只是作为数据变量的声明、修改、调用
//声明
const data = useData({
count: 0,
});
//调用
console.log(data.count);
官网的例子:只用来调用、生成新值用了。
useMounted
useMounted 需要在 mounted 事件中执行的逻辑
useMounted(() => {
console.log("mounted!");
});
useDestroyed
useDestroyed 需要在 destroyed 事件中执行的逻辑
useDestroyed(() => {
console.log("destroyed!");
});
最后贴一个在线测试地址:https://codesandbox.io/s/optimistic-river-rdv22?file=/src/index.js
点击“阅读原文”跳转到vue-hook仓库。
让我们一起携手同走前端路!
长按下图识别二维码 关注公众号回复【加群】即可