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

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

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

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

 

接下來我們來一起了解。

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

一、hooks: 什么叫大勢所趨?

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

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

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

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

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

 

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

二、什么是 hooks?

年輕時你不懂我,就像后來我不懂 hooks。

2.1 hooks 的定義

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

系統(tǒng)運行到某一時期時,會調(diào)用被注冊到該時機的回調(diào)函數(shù)。

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

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

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

在 react@16.x 之前,當我們談論 hooks 時,我們可能談論的是“組件的生命周期”。

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

以 react 為例,hooks 是:

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

簡化一下:

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

(記住這個關鍵詞: 函數(shù)式組件

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

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

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

(關鍵詞:組合式API

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

如:useSlots、 useAttrs、 useRouter 等。

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

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

 

如果按這個標準來看的話,vue 和 react 中 hooks 的定義,似乎都差不多。

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

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

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

為什么?

因為 (愛情 誤) 約定。

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

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

 

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

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

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

因為是約定,因而 useXxx 的命名并非強制,你依然可以將你自定義的 hook 命名為 byXxx 或其他方式,但不推薦。

因為約定的力量在于:我們不用細看實現(xiàn),也能通過命名來了解一個它是什么。

以上 “一個假設、兩個只在” 總結自 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)復用

懟的就是你,mixin !

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

假設有如下需求:

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

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

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

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

// 混入文件:name-mixin.js
export default {
  data() {
    return {
      name: genRandomName() // 假裝它能生成隨機的名字
    }
  },
  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 似乎提供了非常不錯的復用能力,但是,react官方文檔直接表明:

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

 

為什么呢?

因為 mixins 雖然提供了這種狀態(tài)復用的能力,但它的弊端實在太多了

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

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

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

又或者:

a.js mixins: [b.js]

b.js mixins: [c.js]

c.js mixins: [d.js]

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

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

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

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

這種時候,你會深深懷疑,mixins 究竟是不是一種科學的復用方式。

弊端三:梅開二度?代價很大!

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

當然,也是有解決方案的,如:

// 動態(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'),
  ]
}

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

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

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


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

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

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

相比于 mixins,它們簡直太棒了!

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

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

3.2 代碼組織

熵減,宇宙哲學到編碼哲學。

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

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

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

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

 

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

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

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

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

3.3 比 class 組件更容易理解

尤其是 this 。

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

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

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

但在Hooks 寫法中,你就完全不必擔心 this 的問題了。

因為:

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

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

媽媽再也不用擔心我忘記寫 bind 了。

3.4 友好的漸進式

隨風潛入夜,潤物細無聲。

漸進式的含義是:你可以一點點深入使用。

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

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

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

四、如何開始玩 hooks ?

4.1 環(huán)境和版本

在 react 項目中, react 的版本需要高于 16.8.0。

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

4.2 react 的 Hooks 寫法

因為 react Hooks 僅支持“函數(shù)式”組件,因此需要創(chuàng)建一個函數(shù)式組件 my-component.js。

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

export default () => {
  // 通過 useState 可以創(chuàng)建一個 狀態(tài)屬性 和一個賦值方法
  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>
}

細節(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'
// 定義了一個 ref 對象
const name = ref('')
// 定義了一個依賴 name.value 的計算屬性
const message = computed(() => {
  return `hello, my name is ${name.value}`
})
</script>

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

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

參考網(wǎng)址:

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

五、開始第一個自定義 hook

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

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

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

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

 

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

5.1 react 玩家看這里

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

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

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

如果我們要實現(xiàn)上面效果,我們該怎么寫代碼呢?

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 的函數(shù)組件被渲染一次時,genRandom() 方法就會被執(zhí)行一次,雖然不影響 name 的值,但存在性能消耗,甚至產(chǎn)生其他 bug。

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

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

5.2 vue 玩家看這里

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

目標也定位實現(xiàn)一個 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 的異同

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

本文轉載于掘金,謝謝,大家一起學習…!

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

分享到:
標簽:Hooks
用戶無頭像

網(wǎng)友整理

注冊時間:

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

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

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

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

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

答題星2018-06-03

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

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數(shù)有氧達人2018-06-03

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

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

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

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定