亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

hooks有哪些特點

發布時間:2022-03-02 09:08:25 來源:億速云 閱讀:179 作者:iii 欄目:編程語言

本篇內容主要講解“hooks有哪些特點”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“hooks有哪些特點”吧!

hooks有哪些特點

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

2019年年初,react16.8.x 版本正式具備了 hooks 能力。

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

在后續的 reactvue3 相關版本中,相關 hooks 能力都開始被更多人所接受。

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

hooks有哪些特點

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

二、什么是 hooks

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

2.1 hooks 的定義

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

系統運行到某一時期時,會調用被注冊到該時機的回調函數。

比較常見的鉤子有:windows 系統的鉤子能監聽到系統的各種事件,瀏覽器提供的 onloadaddEventListener 能注冊在瀏覽器各種時機被調用的方法。

以上這些,都可以被稱一聲 "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!

如:useSlotsuseAttrsuseRouter 等。

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

hooks有哪些特點

如果按這個標準來看的話,vuereacthooks 的定義,似乎都差不多。

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

2.2 命名規范 和 指導思想

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

為什么?

因為(愛情 誤)約定。

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

hooks有哪些特點

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

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

第二個只在: 只在最頂層使用 Hook,而不要在循環,條件或嵌套函數中調用 Hook。

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

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

三、為什么我們需要 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
<template>
  <div>{{ name }}</div>
<template>
<script>
import nameMixin from './name-mixin';
export default {
  mixins: [nameMixin],
  // 通過mixins, 你可以直接獲得 nameMixin 中所定義的狀態、方法、生命周期中的事件等
  mounted() {
    setTimeout(() => {
      this.setName('Tom')
    }, 3000)
  }
}
<script>

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

hooks有哪些特點

為什么呢?

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

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

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

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

又或者:

a.js mixins: [b.js]

b.js mixins: [c.js]

c.js mixins: [d.js]

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

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

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

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

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

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

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

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

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

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

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

Hook 的狀態復用寫法:

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

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

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

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

  1. 方法和屬性好追溯嗎?這可太好了,誰產生的,哪兒來的一目了然。

  2. 會有重名、覆蓋問題嗎?完全沒有!內部的變量在閉包內,返回的變量支持定義別名。

  3. 多次使用,沒開N度?你看上面的代碼塊內不就“梅開三度” 了嗎?

就沖 “狀態邏輯復用” 這個理由,Hooks 就已經香得我口水直流了。

3.2 代碼組織

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

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

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

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

hooks有哪些特點

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

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

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

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

3.3 比 class 組件更容易理解

尤其是 this

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

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

很顯然,綁定雖然“必要”,但并不是“優點”,反而是“故障高發”地段。

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

因為:

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

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

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

3.4 友好的漸進式

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

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

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

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

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

四、如何開始玩 hooks

4.1 環境和版本

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

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

4.2 react 的 Hooks 寫法

因為 react Hooks 僅支持“函數式”組件,因此需要創建一個函數式組件 my-component.js

// my-component.js
import { 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>
}

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里完成 useStateuseMemo 相關工作的 API 并沒有通過 useXxx 來命名,而是遵從了 Vue 一脈相承而來的 refcomputed

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

五、開始第一個自定義 hook

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

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

hooks有哪些特點

那么,我們應該怎么開始撰寫 “自定義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.3 vuereact 自定義 Hook 的異同

  • 相似點: 總體思路是一致的 都遵照著 "定義狀態數據","操作狀態數據","隱藏細節" 作為核心思路。

  • 差異點: 組合式APIReact函數組件 有著本質差異
    vue3 的組件里, setup 是作為一個早于 “created” 的生命周期存在的,無論如何,在一個組件的渲染過程中只會進入一次。
    React函數組件 則完全不同,如果沒有被 memorized,它們可能會被不停地觸發,不停地進入并執行方法,因此需要開銷的心智相比于vue其實是更多的。

到此,相信大家對“hooks有哪些特點”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

革吉县| 龙岩市| 仁寿县| 汾西县| 平泉县| 尉犁县| 张家界市| 怀集县| 延津县| 德钦县| 广丰县| 高平市| 云南省| 新巴尔虎左旗| 威信县| 镇沅| 佳木斯市| 兴仁县| 宁明县| 巴林右旗| 广饶县| 孝感市| 保定市| 景谷| 闻喜县| 横山县| 荥阳市| 荔浦县| 浦东新区| 乐昌市| 云霄县| 磴口县| 淳安县| 莆田市| 临朐县| 芮城县| 牟定县| 三江| 道孚县| 新兴县| 无锡市|