這篇文章我們來了解下hooks,聊聊為什麼vue和react都選擇它,為什麼我們需要 hooks ,以及vue 和 react 自訂 Hook 的異同,希望對大家有所幫助!
#初步了解Hooks
在vue
與react
的現況
聽一聽本文作者關於Hooks
的定義與總結
弄清楚「為什麼我們需要Hooks
」
進行一些簡單的Hooks
實踐
2019年初,react
在16.8.x
版本正式具備了hooks
能力。
2019年6月,尤雨溪在vue/github-issues裡提出了關於vue3 Component API
的提案。 (vue hooks的基礎)
在後續的react
和vue3
相關版本中,相關版本hooks
能力都開始被更多人所接受。 【相關推薦:vuejs影片教學】
除此之外,solid.js
、preact
等框架,也是開始選擇加入hooks
大家庭。
可以預見,雖然目前仍然是class Component
和hooks api
並駕齊驅的場面,但未來幾年裡,hooks
極有可能取代class Component
成為業界真正的主流。
hooks
?年輕時你不懂我,就像後來我不懂
hooks
。
hooks
的定義"hooks" 直譯是“鉤子”,它並不僅是react
,甚至不僅是前端界的專用術語,而是整個產業所熟知的用語。通常指:
系統運行到某一時期時,會呼叫被註冊到該時機的回呼函數。
比較常見的鉤子有:windows
系統的鉤子能監聽到系統的各種事件,瀏覽器提供的onload
或addEventListener
能註冊在瀏覽器各種時機被呼叫的方法。
以上這些,都可以被稱一聲 "hook"。
但是很顯然,在特定領域的特定話題下,hooks
這個字被賦予了一些特殊的意義。
在react@16.x
之前,當我們談論hooks
時,我們可能談論的是「元件的生命週期」。
但現在,hooks
則有了全新的意義。
以react
為例,hooks
是:
一系列以
「use」
開頭的方法,它們提供了讓你可以完全避開class式寫法
,在函數式元件中完成生命週期、狀態管理、邏輯復用等幾乎全部元件開發工作的能力。
簡化一下:
一系列方法,提供了在函數式元件中完成開發工作的能力。
(記住這個關鍵字:函數式元件)
import { useState, useEffect, useCallback } from 'react'; // 比如以上这几个方法,就是最为典型的 Hooks
而在vue
中,hooks
的定義可能更模糊,姑且總結一下:
在
vue
組合式API裡,以“use”
作為開頭的,一系列提供了元件復用、狀態管理等開發能力的方法。
(關鍵字:組合式API)
import { useSlots, useAttrs } from 'vue'; import { useRouter } from 'vue-router'; // 以上这些方法,也是 vue3 中相关的 Hook!
如:useSlots
、useAttrs
、useRouter
等。
但主觀來說,我認為vue
組合式API本身就是「vue hooks」的關鍵一環,起到了react hooks
裡對生命週期、狀態管理的核心角色。 (如onMounted
、ref
等等)。
如果按這個標準來看的話,vue
和react
中hooks
的定義,似乎都差不多。
那為什麼要提到是以「use」
作為開頭的方法呢?
通常來說,hooks
的命名都是以use
作為開頭,這個規範也包括了那麼我們自訂的hooks
。
為什麼?
因为(爱情 误)约定。
在react
官方文档里,对hooks
的定义和使用提出了“一个假设、两个只在”核心指导思想。(播音腔)
一个假设:假设任何以 「use
」 开头并紧跟着一个大写字母的函数就是一个Hook
。
第一个只在:只在React
函数组件中调用Hook
,而不在普通函数中调用Hook
。(Eslint
通过判断一个方法是不是大坨峰命名来判断它是否是React
函数)
第二个只在:只在最顶层使用Hook
,而不要在循环,条件或嵌套函数中调用 Hook。
因为是约定,因而useXxx
的命名并非强制,你依然可以将你自定义的hook
命名为byXxx
或其他方式,但不推荐。
因为约定的力量在于:我们不用细看实现,也能通过命名来了解一个它是什么。
以上“一个假设、两个只在”总结自react
官网:
https://zh-hans.reactjs.org/docs/hooks-rules.html
https://zh-hans.reactjs.org/docs/hooks-faq.html#what-exactly-do-the-lint-rules-enforce
hooks
?3.1 更好的状态复用
怼的就是你,
mixin
!
在class
组件模式下,状态逻辑的复用是一件困难的事情。
假设有如下需求:
当组件实例创建时,需要创建一个
state
属性:name
,并随机给此name
属性附一个初始值。除此之外,还得提供一个setName
方法。你可以在组件其他地方开销和修改此状态属性。
更重要的是: 这个逻辑要可以复用,在各种业务组件里复用这个逻辑。
在拥有Hooks
之前,我首先会想到的解决方案一定是mixin
。
代码如下:(此示例采用vue2 mixin
写法 )
// 混入文件:name-mixin.js export default { data() { return { name: genRandomName() // 假装它能生成随机的名字 } }, methods: { setName(name) { this.name = name } } }
// 组件:my-component.vue{{ name }}
很明显,vue
组合式API里完成useState
和useMemo
相关工作的API
并没有通过useXxx
来命名,而是遵从了Vue
一脉相承而来的ref
和computed
。
虽然不符合react Hook
定义的Hook
约定,但vue
的api
不按照react
的约定好像也并没有什么不妥。
参考网址:https://v3.cn.vuejs.org/api/composition-api.html
hook
除了官方提供的Hooks Api
,Hooks
的另外一个重要特质,就是可以自己进行“自定义 Hooks” 的定义,从而完成状态逻辑的复用。
开源社区也都有很多不错的基于Hooks
的封装,比如ahooks
(ahooks.js.org/zh-CN/),又比如vueuse
(vueuse.org/)
我还专门写过一篇小文章介绍
vuehook
:
【一库】vueuse:我不许身为vuer,你的工具集只有lodash!。
https://juejin.cn/post/7030395303433863205
那么,我们应该怎么开始撰写 “自定义Hooks” 呢?往下看吧!
5.1 react 玩家看这里
react
官方网站就专门有一个章节讲述“自定义Hook”。(https://react.docschina.org/docs/hooks-custom.html)
这里,我们扔用文章开头那个useName
的需求为例,希望达到效果:
const { name, setName } = useName(); // 随机生成一个状态属性 name,它有一个随机名作为初始值 // 并且提供了一个可随时更新该值的方法 setName
如果我们要实现上面效果,我们该怎么写代码呢?
import React from 'react'; export const useName = () => { // 这个 useMemo 很关键 const randomName = React.useMemo(() => genRandomName(), []); const [ name, setName ] = React.useState(randomName) return { name, setName } }
忍不住要再次感叹一次,和mixins
相比,它不仅使用起来更棒,就连定义起来也那么简单。
可能有朋友会好奇,为什么不直接这样写:
const [ name, setName ] = React.useState(genRandomName())
因为这样写是不对的,每次使用该Hook
的函数组件被渲染一次时,genRandom()
方法就会被执行一次,虽然不影响name
的值,但存在性能消耗,甚至产生其他bug
。
为此,我写了一个能复现错误的demo,有兴趣的朋友可以点开验证:https://codesandbox.io/s/long-cherry-kzcbqr
2022-02-03日补充更正:经掘友提醒,可以通过 React.useState(() => randomName()) 传参来避免重复执行,这样就不需要 useMemo 了,感谢!
5.2 vue 玩家看这里
vue3
官网没有关于自定义Hook
的玩法介绍,但实践起来也并不困难。
目标也定位实现一个useName
方法:
import { ref } from 'vue'; export const useName = () => { const name = ref(genRandomName()) const setName = (v) => { name.value = v } return { name, setName } }
5.3vue
和react
自定义Hook
的异同
相似点: 总体思路是一致的 都遵照着 "定义状态数据","操作状态数据","隐藏细节" 作为核心思路。
差异点:组合式API
和React函数组件
有着本质差异vue3
的组件里,setup
是作为一个早于 “created” 的生命周期存在的,无论如何,在一个组件的渲染过程中只会进入一次。React函数组件
则完全不同,如果没有被memorized
,它们可能会被不停地触发,不停地进入并执行方法,因此需要开销的心智相比于vue
其实是更多的。
本文转载自:https://juejin.cn/post/7066951709678895141
作者:春哥的梦想是摸鱼
以上是hooks怎麼樣,為什麼vue和react都選擇它!的詳細內容。更多資訊請關注PHP中文網其他相關文章!