日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當(dāng)前位置:首頁(yè) > 科技  > 軟件

useEffect 實(shí)踐案例:自定義 Hook

來(lái)源: 責(zé)編: 時(shí)間:2023-12-21 17:11:29 204觀看
導(dǎo)讀我們將在上一章案例的基礎(chǔ)之上學(xué)習(xí)自定義 hook。在上一章中,我們巧妙的把大量的 JSX 邏輯處理封裝在了 List 組件中,使得在頁(yè)面組件的代碼變得非常簡(jiǎn)單。這是針對(duì) UI 層的邏輯處理,那么在數(shù)據(jù)的處理上,是否也能夠進(jìn)行一些

Mhc28資訊網(wǎng)——每日最新資訊28at.com

我們將在上一章案例的基礎(chǔ)之上學(xué)習(xí)自定義 hook。Mhc28資訊網(wǎng)——每日最新資訊28at.com

在上一章中,我們巧妙的把大量的 JSX 邏輯處理封裝在了 List 組件中,使得在頁(yè)面組件的代碼變得非常簡(jiǎn)單。這是針對(duì) UI 層的邏輯處理,那么在數(shù)據(jù)的處理上,是否也能夠進(jìn)行一些封裝呢?Mhc28資訊網(wǎng)——每日最新資訊28at.com

// 數(shù)據(jù)的主要核心邏輯const str = useRef('')const [list, setList] = useState<string[]>([])const [error, setError] = useState('')const [loading, setLoading] = useState(true)function getList() {  searchApi(str.current).then(res => {    setList(res)    setLoading(false)    setError('')  }).catch(err => {    setLoading(false)    setError(err)  })}useEffect(() => {  loading && getList()}, [loading])function onSure() {  setLoading(true)}

答案是肯定的,解決方案就是我們將要在本章中學(xué)習(xí)的自定義 hook。Mhc28資訊網(wǎng)——每日最新資訊28at.com

一、自定義hook

我們常常會(huì)封裝一個(gè)函數(shù)用于邏輯的復(fù)用。自定義 hook 也是這樣的一個(gè)在 react 組件內(nèi)部用于邏輯復(fù)用的函數(shù)封裝。Mhc28資訊網(wǎng)——每日最新資訊28at.com

和普通函數(shù)封裝相比,他唯一的特殊之處就在于我們常常會(huì)將 react 內(nèi)置 hook 封裝在邏輯之中,比如 useState,useEffect 等。除此之外,為了區(qū)分與普通的函數(shù)封裝,我們必須以 use 開(kāi)頭為自定義 hook 命名,這樣的 hook 只能在 React 組件中使用。Mhc28資訊網(wǎng)——每日最新資訊28at.com

以上一章中的數(shù)據(jù)處理邏輯為例,我們來(lái)封裝一個(gè)自定義 hook,將其命名為 useFetch。Mhc28資訊網(wǎng)——每日最新資訊28at.com

function useFetch() {}

我們先考慮單個(gè)場(chǎng)景的封裝,單純只是為了讓組件看上去更簡(jiǎn)潔。Mhc28資訊網(wǎng)——每日最新資訊28at.com

我們就可以把所有的數(shù)據(jù)和處理數(shù)據(jù)的邏輯封裝起來(lái)。Mhc28資訊網(wǎng)——每日最新資訊28at.com

import {useEffect, useState, useRef} from 'react'import { searchApi } from './api'export default function useFetch() {  const str = useRef('')  const [list, setList] = useState<string[]>([])  const [error, setError] = useState('')  const [loading, setLoading] = useState(true)  function getList() {    searchApi(str.current).then(res => {      setList(res)      setLoading(false)      setError('')    }).catch(err => {      setLoading(false)      setError(err)    })  }  useEffect(() => {    loading && getList()  }, [loading])  return { str, list, error, loading, setLoading }}

封裝過(guò)程非常簡(jiǎn)單,就是把之前那一堆邏輯全部遷移過(guò)來(lái),最后返回應(yīng)用組件里需要的數(shù)據(jù)和方法即可。Mhc28資訊網(wǎng)——每日最新資訊28at.com

return { str, list, error, loading, setLoading }

OK,此時(shí)我們來(lái)觀察一下組件里的代碼。Mhc28資訊網(wǎng)——每日最新資訊28at.com

export default function DemoOneNormal() {  const {loading, setLoading, str, list, error} = useFetch()    return (    <Block className={s.container} title={td.title} desc={td.desc}>      <div className={r.flex}>        <input          className={s.input}          placeholder="請(qǐng)輸入您要搜索的內(nèi)容"          onChange={(e) => str.current = e.target.value}        />        <Button          className={s.button}          onClick={() => setLoading(true)}        >          搜索        </Button>      </div>      <List        list={list}        loading={loading}        error={error}        renderItem={(item) => (          <div key={item} className={s.item}>{item}</div>        )}      />    </Block>  )}

邏輯簡(jiǎn)潔了許多。變成了簡(jiǎn)單的同步代碼:通過(guò)一個(gè)方法獲取數(shù)據(jù),并將數(shù)據(jù)渲染到 UI 組件。Mhc28資訊網(wǎng)——每日最新資訊28at.com

Block 組件是單獨(dú)封裝的布局組件,希望不要因此造成任何理解上的困難。Mhc28資訊網(wǎng)——每日最新資訊28at.com

一個(gè)組件變成了數(shù)據(jù)與UI的結(jié)合。我們分別將復(fù)雜的數(shù)據(jù)處理邏輯封裝在 hook 里,將復(fù)雜的UI交互邏輯封裝在基礎(chǔ) UI 組件里,在使用時(shí),利用他們的封裝結(jié)果進(jìn)行組合,能夠簡(jiǎn)單,高效的組合出復(fù)雜的頁(yè)面,這也是我們?cè)趯?shí)踐中最大的追求Mhc28資訊網(wǎng)——每日最新資訊28at.com

這里有些人可能會(huì)有一些疑問(wèn),我只是把一些邏輯放在了另外的地方,代碼量最終不僅沒(méi)有減少,反而還變多了,這樣做的好處真的有那么大嗎?當(dāng)然,因?yàn)槲覀兎庋b的 useFetch 和 List 組件,他們承載了大多數(shù)的復(fù)雜邏輯,并且只會(huì)在最開(kāi)始的時(shí)候編寫(xiě)一次,在以后的使用中,就直接引入使用就行了,這極大的簡(jiǎn)化了后續(xù)的開(kāi)發(fā)工作量,對(duì)工作效率的提高非常顯著Mhc28資訊網(wǎng)——每日最新資訊28at.com

二、進(jìn)一步思考

此時(shí)的封裝雖然足夠簡(jiǎn)潔。但是沒(méi)有考慮復(fù)用。因此還需要進(jìn)一步思考改進(jìn)。Mhc28資訊網(wǎng)——每日最新資訊28at.com

我們來(lái)分析一下場(chǎng)景:每一個(gè)需要信息展示的頁(yè)面,基本邏輯都是在初始化時(shí),請(qǐng)求接口,獲得數(shù)據(jù),然后展示信息。我們可以把不同情況的接口請(qǐng)求抽象成為一個(gè)接口,然后基于這個(gè)場(chǎng)景來(lái)思考不同頁(yè)面的請(qǐng)求的共性與差異。Mhc28資訊網(wǎng)——每日最新資訊28at.com

每個(gè)頁(yè)面都要處理信息展示、異常等邏輯,差異的地方就在于獲取數(shù)據(jù)的 api 函數(shù)不一樣,他返回的數(shù)據(jù)內(nèi)容,數(shù)據(jù)類(lèi)型也不一樣。Mhc28資訊網(wǎng)——每日最新資訊28at.com

不一樣的東西作為參數(shù)傳入,那我們只需要將 api 函數(shù)作為參數(shù)傳入即可。Mhc28資訊網(wǎng)——每日最新資訊28at.com

const info = useFetch(searchApi)

不過(guò)我們此時(shí)還需要考慮的是,為了確保自定義 hook 的返回類(lèi)型具備完整準(zhǔn)確的類(lèi)型推導(dǎo),我們還需要約定傳入 api 的參數(shù)類(lèi)型與返回類(lèi)型。Mhc28資訊網(wǎng)——每日最新資訊28at.com

因此,在定義 useFetch 時(shí),我們先用 ts 約定 api 的具體類(lèi)型,因?yàn)閰?shù)類(lèi)型和返回值類(lèi)型在封裝時(shí)都不確定,只能在具體的實(shí)參傳入之后才能明確,因此使用兩個(gè)泛型來(lái)分別表示參數(shù)類(lèi)型和返回值類(lèi)型。Mhc28資訊網(wǎng)——每日最新資訊28at.com

type API<T, P>   = (param?: P) => Promise<T>

正常代碼不會(huì)這樣換行,之所以這樣只是為了在移動(dòng)端能夠更多的展示代碼信息而不用滾動(dòng)查看。Mhc28資訊網(wǎng)——每日最新資訊28at.com

然后在定義 useFetch 時(shí)傳入這兩個(gè)泛型即可,完整代碼如下:Mhc28資訊網(wǎng)——每日最新資訊28at.com

import { useEffect, useState, useRef } from 'react'type API<T, P> = (param?: P) => Promise<T>export default function useFetch<T, P>(api: API<T, P>) {  const param = useRef<P>()  const [list, setList] = useState<T>()  const [error, setError] = useState('')  const [loading, setLoading] = useState(true)  function getList() {    api(param.current).then(res => {      setList(res)      setLoading(false)      setError('')    }).catch(err => {      setLoading(false)      setError(err)    })  }  useEffect(() => {    loading && getList()  }, [loading])  return {     param,     setParam: (p: P) => param.current = p,    list,     error,     loading,     setLoading   }}

因?yàn)樵谑褂脮r(shí),傳入的 api 函數(shù)已經(jīng)具備了完善的類(lèi)型,因此我們這種寫(xiě)法可以借助 ts 內(nèi)部的自動(dòng)推導(dǎo)而簡(jiǎn)化使用時(shí)在 ts 上的繁瑣。Mhc28資訊網(wǎng)——每日最新資訊28at.com

Mhc28資訊網(wǎng)——每日最新資訊28at.com

const {  loading,   setLoading,   setParam,  list,  error} = useFetch(searchApi)

雖然在使用層面沒(méi)有任何 ts 的痕跡,但是返回值的類(lèi)型已經(jīng)非常明確。Mhc28資訊網(wǎng)——每日最新資訊28at.com

Mhc28資訊網(wǎng)——每日最新資訊28at.com

由于在封裝過(guò)程中我們沒(méi)有處理默認(rèn)值的情況,因此返回類(lèi)型可能為 undefined,這在實(shí)踐中一定要引起重視。你可以根據(jù)實(shí)際情況往 useFetch 傳入默認(rèn)值,也可以在使用層面初始化默認(rèn)值Mhc28資訊網(wǎng)——每日最新資訊28at.com

const {  loading,   setLoading,   setParam,  list = [],  error} = useFetch(searchApi)

這樣,一個(gè)通用,高效,且具備準(zhǔn)確類(lèi)型提示的 hook 就被我們封裝好了。Mhc28資訊網(wǎng)——每日最新資訊28at.com

在實(shí)踐過(guò)程中,由于不同的團(tuán)隊(duì)有不同的需求,你還需要根據(jù)自己的需求和項(xiàng)目實(shí)際情況做相應(yīng)的細(xì)節(jié)調(diào)整,切記不要完整套用。Mhc28資訊網(wǎng)——每日最新資訊28at.com

三、取舍

由于面試的影響,讓不少前端同行錯(cuò)誤的把性能當(dāng)成了實(shí)踐中最重要的標(biāo)準(zhǔn)。但其實(shí)工作中性能并不是最高的優(yōu)先級(jí)。我們往往會(huì)在可接受的范圍之內(nèi),犧牲性能換取其他的便利。Mhc28資訊網(wǎng)——每日最新資訊28at.com

例如,多一層函數(shù)封裝,其實(shí)也就意味著執(zhí)行壓力多那么一點(diǎn)點(diǎn)。但是他可能換來(lái)的是開(kāi)發(fā)效率的極大提高。Mhc28資訊網(wǎng)——每日最新資訊28at.com

因此,在我們的課程案例決策當(dāng)中,提供的方案并不會(huì)把性能當(dāng)做第一準(zhǔn)則,代碼的可讀性、可維護(hù)性、開(kāi)發(fā)效率的優(yōu)先級(jí)都會(huì)比性能更高。只要我們?cè)趯?xiě)代碼的過(guò)程中,非常明確的知道這種方式我們舍棄了什么,得到了什么,你權(quán)衡之后,愿意做出這樣的取舍,那么這樣的方式就是可以使用的。Mhc28資訊網(wǎng)——每日最新資訊28at.com

當(dāng)然,性能依然非常重要,如果你的頁(yè)面出現(xiàn)了卡頓,我們就應(yīng)該思考一下,是不是對(duì)性能的犧牲有點(diǎn)過(guò)了頭。Mhc28資訊網(wǎng)——每日最新資訊28at.com

本文鏈接:http://www.www897cc.com/showinfo-26-51248-0.htmluseEffect 實(shí)踐案例:自定義 Hook

聲明:本網(wǎng)頁(yè)內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問(wèn)題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。郵件:2376512515@qq.com

上一篇: 研發(fā)提效必備技能:25張圖手把手教你基于Docker搭建Maven私服倉(cāng)庫(kù)

下一篇: 看完后,你再也不用怕面試問(wèn)并發(fā)編程啦

標(biāo)簽:
  • 熱門(mén)焦點(diǎn)
Top 主站蜘蛛池模板: 礼泉县| 新兴县| 凤冈县| 长宁区| 全南县| 海兴县| 犍为县| 清丰县| 富源县| 佛教| 博客| 瑞丽市| 德保县| 凤阳县| 买车| 株洲市| 苍南县| 汾西县| 金昌市| 茶陵县| 嘉义县| 丰镇市| 奉新县| 新源县| 利川市| 定州市| 中方县| 安塞县| 阜康市| 新乐市| 神池县| 高密市| 老河口市| 镇坪县| 靖远县| 吉木乃县| 于田县| 儋州市| 安丘市| 留坝县| 鄢陵县|