日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長(zhǎng)提供免費(fèi)收錄網(wǎng)站服務(wù),提交前請(qǐng)做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(wù)(50元/站),

點(diǎn)擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會(huì)員:747

vue和react中使用Hooks的優(yōu)勢(shì)

 

接下來我們來一起了解。

  1. 初步了解 Hooks 在 vue 與 react 的現(xiàn)狀
  2. 聽一聽本文作者關(guān)于 Hooks 的定義和總結(jié)
  3. 弄懂“為什么我們需要 Hooks”
  4. 進(jìn)行一些簡(jiǎn)單的 Hooks 實(shí)踐

一、hooks: 什么叫大勢(shì)所趨?

2019年年初,react 在 16.8.x 版本正式具備了 hooks 能力。

2019年6月,尤雨溪在 vue/github-issues 里提出了關(guān)于 vue3 Component API 的提案。(vue hooks的基礎(chǔ))

在后續(xù)的 react 和 vue3 相關(guān)版本中,相關(guān) hooks 能力都開始被更多人所接受。

除此之外,solid.js、 preact 等框架,也是開始選擇加入 hooks 大家庭。

vue和react中使用Hooks的優(yōu)勢(shì)

 

可以預(yù)見,雖然目前仍然是 class Component 和 hooks api 并駕齊驅(qū)的場(chǎng)面,但未來幾年里,hooks 極有可能取代 class Component 成為業(yè)內(nèi)真正的主流。

二、什么是 hooks?

年輕時(shí)你不懂我,就像后來我不懂 hooks。

2.1 hooks 的定義

"hooks" 直譯是 “鉤子”,它并不僅是 react,甚至不僅是前端界的專用術(shù)語,而是整個(gè)行業(yè)所熟知的用語。通常指:

系統(tǒng)運(yùn)行到某一時(shí)期時(shí),會(huì)調(diào)用被注冊(cè)到該時(shí)機(jī)的回調(diào)函數(shù)。

比較常見的鉤子有:windows 系統(tǒng)的鉤子能監(jiān)聽到系統(tǒng)的各種事件,瀏覽器提供的 onload 或 addEventListener 能注冊(cè)在瀏覽器各種時(shí)機(jī)被調(diào)用的方法。

以上這些,都可以被稱一聲 "hook"。

但是很顯然,在特定領(lǐng)域的特定話題下,hooks 這個(gè)詞被賦予了一些特殊的含義。

在 [email protected] 之前,當(dāng)我們談?wù)?nbsp;hooks 時(shí),我們可能談?wù)摰氖?ldquo;組件的生命周期”。

但是現(xiàn)在,hooks 則有了全新的含義。

以 react 為例,hooks 是:

一系列以 “use” 作為開頭的方法,它們提供了讓你可以完全避開 class式寫法,在函數(shù)式組件中完成生命周期、狀態(tài)管理、邏輯復(fù)用等幾乎全部組件開發(fā)工作的能力。

簡(jiǎn)化一下:

一系列方法,提供了在函數(shù)式組件中完成開發(fā)工作的能力。

(記住這個(gè)關(guān)鍵詞: 函數(shù)式組件

import { useState, useEffect, useCallback } from 'react';
// 比如以上這幾個(gè)方法,就是最為典型的 Hooks

而在 vue 中, hooks 的定義可能更模糊,姑且總結(jié)一下:

在 vue 組合式API里,以 “use” 作為開頭的,一系列提供了組件復(fù)用、狀態(tài)管理等開發(fā)能力的方法。

(關(guān)鍵詞:組合式API

import { useSlots, useAttrs } from 'vue';
import { useRouter } from 'vue-router';
// 以上這些方法,也是 vue3 中相關(guān)的 Hook!

如:useSlots、 useAttrs、 useRouter 等。

但主觀來說,我認(rèn)為vue 組合式API其本身就是“vue hooks”的關(guān)鍵一環(huán),起到了 react hooks里對(duì)生命周期、狀態(tài)管理的核心作用。(如 onMounted、 ref 等等)。

vue和react中使用Hooks的優(yōu)勢(shì)

 

如果按這個(gè)標(biāo)準(zhǔn)來看的話,vue 和 react 中 hooks 的定義,似乎都差不多。

那么為什么要提到是以 “use” 作為開頭的方法呢?

2.2 命名規(guī)范 和 指導(dǎo)思想

通常來說,hooks 的命名都是以 use 作為開頭,這個(gè)規(guī)范也包括了那么我們自定義的 hooks。

為什么?

因?yàn)?nbsp;(愛情 誤) 約定。

在 react 官方文檔里,對(duì) hooks 的定義和使用提出了 “一個(gè)假設(shè)、兩個(gè)只在” 核心指導(dǎo)思想。(播音腔)

vue和react中使用Hooks的優(yōu)勢(shì)

 

一個(gè)假設(shè): 假設(shè)任何以 「use」 開頭并緊跟著一個(gè)大寫字母的函數(shù)就是一個(gè) Hook。

第一個(gè)只在: 只在 React 函數(shù)組件中調(diào)用 Hook,而不在普通函數(shù)中調(diào)用 Hook。(Eslint 通過判斷一個(gè)方法是不是大坨峰命名來判斷它是否是 React 函數(shù))

第二個(gè)只在: 只在最頂層使用 Hook,而不要在循環(huán),條件或嵌套函數(shù)中調(diào)用 Hook。

因?yàn)槭羌s定,因而 useXxx 的命名并非強(qiáng)制,你依然可以將你自定義的 hook 命名為 byXxx 或其他方式,但不推薦。

因?yàn)榧s定的力量在于:我們不用細(xì)看實(shí)現(xiàn),也能通過命名來了解一個(gè)它是什么。

以上 “一個(gè)假設(shè)、兩個(gè)只在” 總結(jié)自 react 官網(wǎng):

  1. https://zh-hans.reactjs.org/docs/hooks-rules.html
  2. https://zh-hans.reactjs.org/docs/hooks-faq.html#what-exactly-do-the-lint-rules-enforce

三、為什么我們需要 hooks ?

3.1 更好的狀態(tài)復(fù)用

懟的就是你,mixin !

在 class 組件模式下,狀態(tài)邏輯的復(fù)用是一件困難的事情。

假設(shè)有如下需求:

當(dāng)組件實(shí)例創(chuàng)建時(shí),需要?jiǎng)?chuàng)建一個(gè) state 屬性:name,并隨機(jī)給此 name 屬性附一個(gè)初始值。除此之外,還得提供一個(gè) setName 方法。你可以在組件其他地方開銷和修改此狀態(tài)屬性。

更重要的是: 這個(gè)邏輯要可以復(fù)用,在各種業(yè)務(wù)組件里復(fù)用這個(gè)邏輯。

在擁有 Hooks 之前,我首先會(huì)想到的解決方案一定是 mixin。

代碼如下:(此示例采用 vue2 mixin 寫法 )

// 混入文件:name-mixin.js
export default {
  data() {
    return {
      name: genRandomName() // 假裝它能生成隨機(jī)的名字
    }
  },
  methods: {
    setName(name) {
      this.name = name
    }
  }
}
// 組件:my-component.vue
<template>
  <div>{{ name }}</div>
<template>
<script>
import nameMixin from './name-mixin';
export default {
  mixins: [nameMixin],
  // 通過mixins, 你可以直接獲得 nameMixin 中所定義的狀態(tài)、方法、生命周期中的事件等
  mounted() {
    setTimeout(() => {
      this.setName('Tom')
    }, 3000)
  }
}
<script>

粗略看來,mixins 似乎提供了非常不錯(cuò)的復(fù)用能力,但是,react官方文檔直接表明:

vue和react中使用Hooks的優(yōu)勢(shì)

 

為什么呢?

因?yàn)?nbsp;mixins 雖然提供了這種狀態(tài)復(fù)用的能力,但它的弊端實(shí)在太多了

弊端一:難以追溯的方法與屬性!

試想一下,如果出現(xiàn)這種代碼,你是否會(huì)懷疑人生:

export default {
  mixins: [ a, b, c, d, e, f, g ], // 當(dāng)然,這只是表示它混入了很多能力
  mounted() {
    console.log(this.name)
    // mmp!這個(gè) this.name 來自于誰?我難道要一個(gè)個(gè)混入看實(shí)現(xiàn)?
  }
}

又或者:

a.js mixins: [b.js]

b.js mixins: [c.js]

c.js mixins: [d.js]

// 你猜猜看, this.name 來自于誰?
// 求求你別再說了,我血壓已經(jīng)上來了

弊端二:覆蓋、同名?貴圈真亂!

當(dāng)我同時(shí)想混入 mixin-a.js 和 mixin-b.js 以同時(shí)獲得它們能力的時(shí)候,不幸的事情發(fā)生了:

由于這兩個(gè) mixin 功能的開發(fā)者惺惺相惜,它們都定義了 this.name 作為屬性。

這種時(shí)候,你會(huì)深深懷疑,mixins 究竟是不是一種科學(xué)的復(fù)用方式。

弊端三:梅開二度?代價(jià)很大!

仍然說上面的例子,如果我的需求發(fā)生了改變,我需要的不再是一個(gè)簡(jiǎn)單的狀態(tài) name,而是分別需要 firstName 和 lastName。此時(shí) name-mixin.js 混入的能力就會(huì)非常尷尬,因?yàn)槲覠o法兩次 mixins 同一個(gè)文件。

當(dāng)然,也是有解決方案的,如:

// 動(dòng)態(tài)生成mixin
function genNameMixin(key, funcKey) {
  return {
    data() {
      return {
        [key]: genRandomName()
      }
    },
    methods: {
      [funcKey]: function(v) {
        this.[key] = v
      } 
    }
  }
}

export default {
  mixins: [
    genNameMixin('firstName', 'setFirstName'),
    genNameMixin('lastName', 'setLastName'),
  ]
}

確實(shí)通過動(dòng)態(tài)生成 mixin 完成了能力的復(fù)用,但這樣一來,無疑更加地增大了程序的復(fù)雜性,降低了可讀性。

因此,一種新的 “狀態(tài)邏輯復(fù)用” 就變得極為迫切了——它就是 Hooks!

Hook 的狀態(tài)復(fù)用寫法:


// 單個(gè)name的寫法
const { name, setName } = useName();

// 梅開二度的寫法
const { name : firstName, setName : setFirstName } = useName();

const { name : secondName, setName : setSecondName } = useName();

相比于 mixins,它們簡(jiǎn)直太棒了!

  1. 方法和屬性好追溯嗎?這可太好了,誰產(chǎn)生的,哪兒來的一目了然。
  2. 會(huì)有重名、覆蓋問題嗎?完全沒有!內(nèi)部的變量在閉包內(nèi),返回的變量支持定義別名。
  3. 多次使用,沒開N度?你看上面的代碼塊內(nèi)不就“梅開三度” 了嗎?

就沖 “狀態(tài)邏輯復(fù)用” 這個(gè)理由,Hooks 就已經(jīng)香得我口水直流了。

3.2 代碼組織

熵減,宇宙哲學(xué)到編碼哲學(xué)。

項(xiàng)目、模塊、頁(yè)面、功能,如何高效而清晰地組織代碼,這一個(gè)看似簡(jiǎn)單的命題就算寫幾本書也無法完全說清楚。

但一個(gè)頁(yè)面中,N件事情的代碼在一個(gè)組件內(nèi)互相糾纏確實(shí)是在 Hooks 出現(xiàn)之前非常常見的一種狀態(tài)。

那么 Hooks 寫法在代碼組織上究竟能帶來怎樣的提升呢?

vue和react中使用Hooks的優(yōu)勢(shì)

 

(假設(shè)上圖中每一種顏色就代碼一種高度相關(guān)的業(yè)務(wù)邏輯)

無論是 vue 還是 react, 通過 Hooks 寫法都能做到,將“分散在各種聲明周期里的代碼塊”,通過 Hooks 的方式將相關(guān)的內(nèi)容聚合到一起。

這樣帶來的好處是顯而易見的:“高度聚合,可閱讀性提升”。伴隨而來的便是 “效率提升,bug變少”

按照“物理學(xué)”里的理論來說,這種代碼組織方式,就算是“熵減”了。

3.3 比 class 組件更容易理解

尤其是 this 。

在 react 的 class 寫法中,隨處可見各種各樣的 .bind(this)。(甚至官方文檔里也有專門的章節(jié)描述了“為什么綁定是必要的?”這一問題)

vue 玩家別笑,computed: { a: () => { this } } 里的 this 也是 undefined。

很顯然,綁定雖然“必要”,但并不是“優(yōu)點(diǎn)”,反而是“故障高發(fā)”地段。

但在Hooks 寫法中,你就完全不必?fù)?dān)心 this 的問題了。

因?yàn)椋?/p>

本來無一物,何處惹塵埃。

Hooks 寫法直接告別了 this,從“函數(shù)”來,到“函數(shù)”去。

媽媽再也不用擔(dān)心我忘記寫 bind 了。

3.4 友好的漸進(jìn)式

隨風(fēng)潛入夜,潤(rùn)物細(xì)無聲。

漸進(jìn)式的含義是:你可以一點(diǎn)點(diǎn)深入使用。

無論是 vue 還是 react,都只是提供了 Hooks API,并將它們的優(yōu)劣利弊擺在了那里。并沒有通過無法接受的 break change 來強(qiáng)迫你必須使用 Hooks 去改寫之前的 class 組件。

你依然可以在項(xiàng)目里一邊寫 class 組件,一邊寫 Hooks 組件,在項(xiàng)目的演進(jìn)和開發(fā)過程中,這是一件沒有痛感,卻悄無聲息改變著一切的事情。

但是事情發(fā)展的趨勢(shì)卻很明顯,越來越多的人加入了 Hooks 和 組合式API 的大軍。

四、如何開始玩 hooks ?

4.1 環(huán)境和版本

在 react 項(xiàng)目中, react 的版本需要高于 16.8.0。

而在 vue 項(xiàng)目中, vue3.x 是最好的選擇,但 vue2.6+ 配合 @vue/composition-api,也可以開始享受“組合式API”的快樂。

4.2 react 的 Hooks 寫法

因?yàn)?react Hooks 僅支持“函數(shù)式”組件,因此需要?jiǎng)?chuàng)建一個(gè)函數(shù)式組件 my-component.js。

// my-component.js
import { useState, useEffect } from 'React'

export default () => {
  // 通過 useState 可以創(chuàng)建一個(gè) 狀態(tài)屬性 和一個(gè)賦值方法
  const [ name, setName ] = useState('')

  // 通過 useEffect 可以對(duì)副作用進(jìn)行處理
  useEffect(() => {
    console.log(name)
  }, [ name ])

  // 通過 useMemo 能生成一個(gè)依賴 name 的變量 message
  const message = useMemo(() => {
    return `hello, my name is ${name}`
  }, [name])

  return <div>{ message }</div>
}

細(xì)節(jié)可參考 react 官方網(wǎng)站:

https://react.docschina.org/docs/hooks-intro.html

4.3 vue 的 Hooks 寫法

vue 的 Hooks 寫法依賴于 組合式API,因此本例采用 <script setup> 來寫:

<template>
  <div>
    {{ message }}
  </div>
</template>
<script setup>
import { computed, ref } from 'vue'
// 定義了一個(gè) ref 對(duì)象
const name = ref('')
// 定義了一個(gè)依賴 name.value 的計(jì)算屬性
const message = computed(() => {
  return `hello, my name is ${name.value}`
})
</script>

很明顯,vue 組合式API里完成 useState 和 useMemo 相關(guān)工作的 API 并沒有通過 useXxx 來命名,而是遵從了 Vue 一脈相承而來的 ref 和 computed。

雖然不符合 react Hook 定義的 Hook 約定,但 vue 的 api 不按照 react 的約定好像也并沒有什么不妥。

參考網(wǎng)址:

https://v3.cn.vuejs.org/api/composition-api.html

五、開始第一個(gè)自定義 hook

除了官方提供的 Hooks Api, Hooks 的另外一個(gè)重要特質(zhì),就是可以自己進(jìn)行“自定義 Hooks” 的定義,從而完成狀態(tài)邏輯的復(fù)用。

開源社區(qū)也都有很多不錯(cuò)的基于 Hooks 的封裝,比如 ahooks (
https://ahooks.js.org/zh-CN/),又比如 vueuse(https://vueuse.org/)

我還專門寫過一篇小文章介紹 vuehook:【一庫(kù)】vueuse:我不許身為vuer,你的工具集只有l(wèi)odash!。

vue和react中使用Hooks的優(yōu)勢(shì)

 

那么,我們應(yīng)該怎么開始撰寫 “自定義Hooks” 呢?往下看吧!

5.1 react 玩家看這里

react 官方網(wǎng)站就專門有一個(gè)章節(jié)講述“自定義Hook”。(
https://react.docschina.org/docs/hooks-custom.html)

這里,我們?nèi)佑梦恼麻_頭那個(gè) useName 的需求為例,希望達(dá)到效果:

const { name, setName } = useName();
// 隨機(jī)生成一個(gè)狀態(tài)屬性 name,它有一個(gè)隨機(jī)名作為初始值
// 并且提供了一個(gè)可隨時(shí)更新該值的方法 setName

如果我們要實(shí)現(xiàn)上面效果,我們?cè)撛趺磳懘a呢?

import React from 'react';

export const useName = () => {
  // 這個(gè) useMemo 很關(guān)鍵
  const randomName = React.useMemo(() => genRandomName(), []);
  const [ name, setName ] = React.useState(randomName)

  return {
    name,
    setName
  }
}

忍不住要再次感嘆一次,和 mixins 相比,它不僅使用起來更棒,就連定義起來也那么簡(jiǎn)單。

可能有朋友會(huì)好奇,為什么不直接這樣寫:

const [ name, setName ] = React.useState(genRandomName())

因?yàn)檫@樣寫是不對(duì)的,每次使用該 Hook 的函數(shù)組件被渲染一次時(shí),genRandom() 方法就會(huì)被執(zhí)行一次,雖然不影響 name 的值,但存在性能消耗,甚至產(chǎn)生其他 bug。

為此,我寫了一個(gè)能復(fù)現(xiàn)錯(cuò)誤的demo,有興趣的朋友可以點(diǎn)開驗(yàn)證:
https://codesandbox.io/s/long-cherry-kzcbqr

2022-02-03日補(bǔ)充更正:經(jīng)掘友提醒,可以通過 React.useState(() => randomName()) 傳參來避免重復(fù)執(zhí)行,這樣就不需要 useMemo 了,感謝!

5.2 vue 玩家看這里

vue3 官網(wǎng)沒有關(guān)于 自定義Hook 的玩法介紹,但實(shí)踐起來也并不困難。

目標(biāo)也定位實(shí)現(xiàn)一個(gè) useName 方法:

import { ref } from 'vue';

export const useName = () => {
  const name = ref(genRandomName())
  const setName = (v) => {
    name.value = v
  }
  return {
    name,
    setName
  }
}

5.3 vue 和 react 自定義 Hook 的異同

  • 相似點(diǎn): 總體思路是一致的 都遵照著 "定義狀態(tài)數(shù)據(jù)","操作狀態(tài)數(shù)據(jù)","隱藏細(xì)節(jié)" 作為核心思路。
  • 差異點(diǎn): 組合式API 和 React函數(shù)組件 有著本質(zhì)差異vue3 的組件里, setup 是作為一個(gè)早于 “created” 的生命周期存在的,無論如何,在一個(gè)組件的渲染過程中只會(huì)進(jìn)入一次。React函數(shù)組件 則完全不同,如果沒有被 memorized,它們可能會(huì)被不停地觸發(fā),不停地進(jìn)入并執(zhí)行方法,因此需要開銷的心智相比于vue其實(shí)是更多的。

本文轉(zhuǎn)載于掘金,謝謝,大家一起學(xué)習(xí)…!

…https://juejin.cn/post/7066951709678895141?share_token=fe63ed48-8486-473a-a1a2-88b14fe41e4a

分享到:
標(biāo)簽:Hooks
用戶無頭像

網(wǎng)友整理

注冊(cè)時(shí)間:

網(wǎng)站:5 個(gè)   小程序:0 個(gè)  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會(huì)員

趕快注冊(cè)賬號(hào),推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫(kù),初中,高中,大學(xué)四六

運(yùn)動(dòng)步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動(dòng)步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績(jī)?cè)u(píng)定2018-06-03

通用課目體育訓(xùn)練成績(jī)?cè)u(píng)定