Hooks之几大框架中的大势所趋

5 篇文章 0 订阅
3 篇文章 0 订阅

​作为一个合格点的不算太牛逼的前端工程师🦁,你得无时无刻都在注意技术方向的势头,而hooks 将是作为装逼大师的你必须掌握的技能点,这也是几大前沿框架发展的一大核心势头,本文着重讲讲React和Vue中hooks的前景及用法,废话不多说直接来正文📢:

一、什么是 hooks

1.1 vue 的定义

2019年6月,尤雨溪在 vue/github-issues 里提出了关于 vue3 Component API 的提案。(vue hooks的基础)

hook是钩子的意思,看到“钩子”是不是就想到了钩子函数?事实上,hooks 还真是函数的一种写法。

vue3 借鉴 react hooks 开发出了 Composition API ,所以也就意味着 Composition API 也能进行自定义封装 hooks。

vue3 中的 hooks 就是函数的一种写法,就是将文件的一些单独功能的js代码进行抽离出来,放到单独的js文件中,或者说是一些可以复用的公共方法/功能。其实 hooks 和 vue2 中的 mixin 有点类似,但是相对 mixins 而言, hooks 更清楚复用功能代码的来源, 更清晰易懂。

1.2 react 的定义

Hook 是 React 16.8 的新增特性。

Hooks本质上就是一类特殊的函数,它们可以为你的函数型组件(function component)注入一些特殊的功能,让您在不编写类的情况下使用 state(状态) 和其他 React 特性。

 

二、 为什么hooks是大势所趋?

从以上可以看到,React 和 Vue3 中都已经相继引入,同时也被越来越多的人接受和广泛使用

除此之外, solid.js、 preact 等框架,也是开始选择加入 hooks 思想,由此可见hooks将是未来几年行业的热门思想和话题。

三、 命名规范 和 指导思想

hooks 的命名都是以 use 作为开头,这个规范也包括了那么我们自定义的 hooks

为什么?

因为约定。

在 react 官方文档里,对 hooks 的定义和使用提出了 “一个假设、两个只在” 核心指导思想。

 

一个假设: 假设任何以 「use」 开头并紧跟着一个大写字母的函数就是一个 Hook

第一个只在: 只在 React 函数组件中调用 Hook,而不在普通函数中调用 Hook。(Eslint 通过判断一个方法是不是大坨峰命名来判断它是否是 React 函数)

第二个只在: 只在最顶层使用 Hook,而不要在循环,条件或嵌套函数中调用 Hook。

因为是约定,因而 useXxx 的命名并非强制,你依然可以将你自定义的 hook 命名为 byXxx 或其他方式,但不推荐。

因为约定的力量在于:我们不用细看实现,也能通过命名来了解一个它是什么。

以上 “一个假设、两个只在” 总结自 react 官网:

  1. zh-hans.reactjs.org/docs/hooks-…

  2. zh-hans.reactjs.org/docs/hooks-…

以上这段摘自“摸鱼的春哥”在【浅谈:为啥vue和react都选择了Hooks🏂】中的介绍,说的非常形象也易懂,可以建议大家读读这篇文章。

四、hooks 存在的场景和解决哪些难题呢?

4.1 vue已经在用的组合api

import { useSlots, useAttrs } from 'vue';import { useRouter } from 'vue-router';// 以上这些方法,也是 vue3 中相关的 Hook!

这些useSlots,useAttrs,useRouter内置的类有没有看起来很眼熟,前面说过定义是什么来着,use+大写字母开头的驼峰,没错,是它,它就是hooks。

已经由原来的Vue和Router类细化为具体的hooks函数。从而提供了组件复用、状态管理等开发能力的方法。

如何玩hooks,这儿来个自定义🌰:

干什么事之前呢,我们经常说要搞清楚前景,不然两眼一抹黑🙂!

场景:封住一个可复用的共用事件集合hooks,类名为 useAddEvent:

vue 的 Hooks 写法依赖于 组合式API,所以依赖 <script setup>或者defineComponent的setUp类;

// src/hooks/useEvent.tsconst useAddEvent = function({element, type, callback}) {    if (element.addEventListener) { // 支持使用 addEventListener()        if (type.slice(0,2) === "on") // 以 "on" 开头,不需要,则去掉            type = type.slice(2);        element.addEventListener(type, callback);    } else if (element.attachEvent) { // 支持使用 attachEvent()        if (type.slice(0, 2) !== "on") // 没有以 "on" 开头,需要,则加上            type = "on" + type;        element.attachEvent(type, callback);    }else{        type.slice(0, 2) !== "on" ? element['on'+ type] = callback : element[type] = callback;    }   }export default useAddEvent;

hook文件的使用:在需要用到该hook功能的组件中的使用,在 test.vue文件中调用如下:

// src/views/test.vue<template>  <div ref="scroll">      </div></template><script lang="ts">import { defineComponent} from 'vue'// 引入hooksimport useAddEvent from '@/hooks/useAddEvent'export default defineComponent({  setup () {    // 使用hooks功能    useAddEvent({        element: this.$refs.scroll,        type: 'scroll', // 触发事件类型,支持on类型        callback: debounce(buriedPoint, 1000){...} // 节流函数处理    });   }})</script>

or

// src/views/test.vue<template>  <div ref="scroll">      </div></template><script setup lang="ts">// import { computed, ref } from 'vue'// 引入hooksimport useAddEvent from '@/hooks/useAddEvent'// 使用hooks功能useAddEvent({    element: this.$refs.scroll,    type: 'scroll', // 触发事件类型,支持on类型    callback: debounce(buriedPoint, 1000){...} // 节流函数处理}); </script>

4.1 react开发时不得不遇到的问题

状态逻辑难以复用: 业务变得复杂之后,组件之间共享状态变得频繁,组件复用和状态逻辑管理就变得十分复杂。使用redux也会加大项目的复杂度和体积。

组成复杂难以维护: 复杂的组件中有各种难以管理的状态和副作用,在同一个生命周期中你可能会因为不同情况写出各种不相关的逻辑,但实际上我们通常希望一个函数只做一件事情。

类的this指向性问题: 我们用class来创建react组件时,为了保证this的指向正确,我们要经常写这样的代码:const that = this,或者是this.handleClick = this.handleClick.bind(this)>;一旦this使用错误,各种bug就随之而来。

为了解决这些麻烦,hooks 允许我们使用简单的特殊函数实现class的各种功能。

react Hooks 仅支持“函数式”组件,因此需要创建一个函数式组件 my-component.js

// my-component.jsimport { useState, useEffect } from 'React'export default () => {  // 通过 useState 可以创建一个 状态属性 和一个赋值方法  const [ name, setName ] = useState('')  // 通过 useEffect 可以对副作用进行处理  useEffect(() => {    console.log(name)  }, [ name ])  // 通过 useMemo 能生成一个依赖 name 的变量 message  const message = useMemo(() => {    return `hello, my name is ${name}`  }, [name])  return <div>{ message }</div>}

useState

在 React 组件中,我们经常要使用 state 来进行数据的实时响应,根据 state 的变化重新渲染组件更新视图。

因为纯函数不能有状态,在 hooks 中,useState就是一个用于为函数组件引入状态(state)的状态钩子。

const [state, setState] = useState(initialState);

useState 的唯一参数是状态初始值(initial state),它返回了一个数组,这个数组的第[0]项是当前当前的状态值,第[1]项是可以改变状态值的方法函数。

useEffect

useEffect(create, deps);

useEffect()用来引入具有副作用的操作,最常见的就是向服务器请求数据。该 Hook 接收一个函数,该函数会在组件渲染到屏幕之后才执行。

和 react 类的生命周期相比,useEffect Hook 可以当做 componentDidMount,componentDidUpdate 和 componentWillUnmount 的组合。默认情况下,react 首次渲染和之后的每次渲染都会调用一遍传给 useEffect 的函数。

useEffect 的性能问题

因为 React 首次渲染和之后的每次渲染都会调用一遍传给 useEffect 的函数,所以大多数情况下很有可能会产生性能问题。

为了解决这个问题,可以将数组作为可选的第二个参数传递给 useEffect。数组中可选择性写 state 中的数据,代表只有当数组中的 state 发生变化是才执行函数内的语句,以此可以使用多个useEffect分离函数关注点。如果是个空数组,代表只执行一次,类似于 componentDidUpdata。

解绑副作用

在 React 类中,经常会需要在组件卸载时做一些事情,例如移除监听事件等。 在 class 组件中,我们可以在 componentWillUnmount 这个生命周期中做这些事情,而在 hooks 中,我们可以通过 useEffect 第一个函数中 return 一个函数来实现相同效果。以下是一个简单的清除定时器例子:

function Counter() {  const [count, setCount] = useState(0);  useEffect(() => {    const timer = setInterval(() => {      setCount(count => count + 1);    }, 1000);    return () => clearInterval(timer);  }, []);  return (    <>      Count: {count}    </>  );}

五、说说vue 和 react 自定义hook的异同

  • 相似点:总体思路是一致的 都遵照着 "定义状态数据","操作状态数据","隐藏细节" 作为核心思路。

  • 差异点:组合式API 和 React函数组件 有着本质差异
    vue3 的组件里, setup 是作为一个早于 “created” 的生命周期存在的,无论如何,在一个组件的渲染过程中只会进入一次。
    React函数组件 则完全不同,如果没有被 memorized,它们可能会被不停地触发,不停地进入并执行方法,因此需要开销的心智相比于vue其实是更多的。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值