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

當前位置:首頁 > 科技  > 軟件

useEffect 實踐案例之一

來源: 責編: 時間:2023-11-30 09:27:54 219觀看
導讀序對于 useEffect 的掌握是 React hooks 學習的重中之重。因此我們還需要花一些篇幅繼續圍繞它講解。在上一篇文章中,我們使用兩個案例分析了 useEffect 的理論知識。接下來,我們通過一些具體的實踐案例來學習 useEffec

CvL28資訊網——每日最新資訊28at.com

對于 useEffect 的掌握是 React hooks 學習的重中之重。因此我們還需要花一些篇幅繼續圍繞它講解。CvL28資訊網——每日最新資訊28at.com

在上一篇文章中,我們使用兩個案例分析了 useEffect 的理論知識。接下來,我們通過一些具體的實踐案例來學習 useEffect 的運用。CvL28資訊網——每日最新資訊28at.com

一、需求

現有一個簡單的需求,要實現一個搜索框,輸入內容之后,點擊搜索按鈕,然后得到一個列表。CvL28資訊網——每日最新資訊28at.com

當列表為空時,顯示暫無數據。CvL28資訊網——每日最新資訊28at.com

CvL28資訊網——每日最新資訊28at.com

接口請求過程中,需要顯示 Loading 狀態。CvL28資訊網——每日最新資訊28at.com

CvL28資訊網——每日最新資訊28at.com

Loading 狀態隨便用的一個轉圈圖標來表示,和下面的圖標有點重疊,以后有機會再調整一下 UI。CvL28資訊網——每日最新資訊28at.com

接口請求成功之后,顯示一個列表。CvL28資訊網——每日最新資訊28at.com

CvL28資訊網——每日最新資訊28at.com

再次搜索時,顯示 Loading 狀態。CvL28資訊網——每日最新資訊28at.com

CvL28資訊網——每日最新資訊28at.com

如果接口請求出錯,顯示錯誤頁面。CvL28資訊網——每日最新資訊28at.com

CvL28資訊網——每日最新資訊28at.com

在實踐中,這是針對一個請求所需要的常規狀態處理,當然很多時候我們在學習的過程中簡化了空數據/Loading/異常等狀態,就導致了許多自學的朋友沒有在工作中友好處理這些狀態的習慣。CvL28資訊網——每日最新資訊28at.com

二、實現

我們一步一步來實現該需求。CvL28資訊網——每日最新資訊28at.com

我們假設一個請求需要花費 600ms,在學習階段,我們可以借助 Promise 與 setTimeout 來模擬一個接口請求。CvL28資訊網——每日最新資訊28at.com

單獨創建一個 api.ts 文件。CvL28資訊網——每日最新資訊28at.com

在該文件中,我們聲明一個名為 searchApi 的函數,該函數接收一個字符串作為參數。CvL28資訊網——每日最新資訊28at.com

我計劃設計該函數最終返回一個 Promise 對象。并將一個字符串數組 resolve 出來。該字符串由搜索條件的一個字符與Math.random 產生的隨機數組成。CvL28資訊網——每日最新資訊28at.com

輸出的列表長這樣。CvL28資訊網——每日最新資訊28at.com

CvL28資訊網——每日最新資訊28at.com

該 api 函數具體代碼如下:CvL28資訊網——每日最新資訊28at.com

// ./api.tsexport function searchApi(param: string) {  return new Promise<string[]>((resolve, reject) => {    const p = param.split('')    const arr: string[] = []    for(var i = 0; i < 10; i++) {      const pindex = i % p.length      arr.push(`${p[pindex] || '^ ^'} - ${Math.random()}`)    }    setTimeout(() => {      if (Math.random() * 10 > 1) {        resolve(arr)      } else {        reject('請求異常,請重新嘗試!')      }    }, 600)  })}

在該函數中,我們使用泛型明確了 Promise 的輸出類型,在后續的使用中就可以利用 TypeScript 的自動類型推導得到具體的返回類型。CvL28資訊網——每日最新資訊28at.com

CvL28資訊網——每日最新資訊28at.com

接下來我們要創建組件函數。CvL28資訊網——每日最新資訊28at.com

// index.tsxexport default function DemoOneNormal() {  // ...}

然后我們根據 UI 的情況去分析應該在代碼中設計哪些數據。CvL28資訊網——每日最新資訊28at.com

首先有一個列表需要展示。CvL28資訊網——每日最新資訊28at.com

const [list, setList] = useState<string[]>([])

然后有一個 Loading 的顯示與隱藏需要控制。CvL28資訊網——每日最新資訊28at.com

const [loading, setLoading] = useState(false)

還有一個錯誤信息需要顯示。CvL28資訊網——每日最新資訊28at.com

const [error, setError] = useState('')

還有一個稍微有一些特殊的,輸入框中輸入的內容。我們要注意準確分析內容:該內容的展示在已有的 UI 中,是根據鍵盤輸入而展示內容,它不由數據來驅動。CvL28資訊網——每日最新資訊28at.com

我們在該案例中,僅僅只是記錄輸入的內容,并傳入 searchApi即可。因此我們可以使用 useRef 來存儲該變量。CvL28資訊網——每日最新資訊28at.com

const str = useRef('')

如果情況有變,有其他的 UI 需要該數據來驅動,那么我們就需要將其調整為使用 useState 來存儲。CvL28資訊網——每日最新資訊28at.com

接下來思考 JSX 代碼的編寫。CvL28資訊網——每日最新資訊28at.com

首先是一個輸入框 input 與按鈕 button。CvL28資訊網——每日最新資訊28at.com

<input   className={s.input}   placeholder="請輸入您要搜索的內容"   notallow={(e) => str.current = e.target.value} /><Button   className={s.button}   onClick={onSure}>  搜索</Button>

案例中的樣式使用了 css module,因此 className 的語法會與前面介紹的有所不同,我們把 s.input 當成一個字符串來看待即可。CvL28資訊網——每日最新資訊28at.com

代碼中,借助 input 的 onChange 回調來記錄當前輸入的值。CvL28資訊網——每日最新資訊28at.com

// const str = useRef('')notallow={(e) => str.current = e.target.value}

點擊按鈕時,修改對應的狀態,并開始發送請求。此時 Loading 應該修改為 true。CvL28資訊網——每日最新資訊28at.com

function onSure() {  setLoading(true)  searchApi(str.current).then(res => {    setList(res)    setLoading(false)    setError('')  }).catch(err => {    setLoading(false)    setError(err)  })}

請求成功之后,Loading 改回 false,list 得到新的數據。如果請求失敗,Loading 依然需要改成 false,并記錄錯誤信息。CvL28資訊網——每日最新資訊28at.com

接下來我們要思考列表的 UI 代碼。CvL28資訊網——每日最新資訊28at.com

首先,空數據、錯誤信息、正常列表的顯示情況是互斥的,他們三個只能存在一個。Loading 狀態是每個情況下都有可能發生的,與他們的關系是分別共存的。CvL28資訊網——每日最新資訊28at.com

因此,當有錯誤信息時,這一塊的內容應該為。CvL28資訊網——每日最新資訊28at.com

if (error) {  return (    <div className={s.wrapper}>      {loading && (        <div className={s.loading_wrapper}>          <Icon spin type='loading' style={{ fontSize: 40 }} />        </div>      )}      <Icon type='event' color='red' style={{ fontSize: 32 }} />      <div className={s.error}>{error}</div>    </div>  )}

案例中出現的 Icon 組件是一個圖標,該組件是我們這個項目自己封裝好的基礎組件。CvL28資訊網——每日最新資訊28at.com

當是空列表時。CvL28資訊網——每日最新資訊28at.com

if (list.length === 0) {  return (    <div className={s.wrapper}>      {loading && (        <div className={s.loading_wrapper}>          <Icon spin type='loading' color='#2860Fa' style={{ fontSize: 38 }} />        </div>      )}      <Icon type='event' color='#ccc' style={{ fontSize: 32 }} />      <div className={s.nodata}>暫無數據</div>    </div>  )}

正常列表有數據時。CvL28資訊網——每日最新資訊28at.com

<div className={s.list}>  {loading && (    <div className={s.loading_wrapper}>      <Icon spin type='loading' color='#2860Fa' style={{ fontSize: 38 }} />    </div>  )}  {list.map(item => (    <div key={item} className={s.item}>{item}</div>  ))}</div>

OK,此時所有的邏輯已經考慮完畢。CvL28資訊網——每日最新資訊28at.com

三、優化封裝

我們會發現,列表相關的邏輯實在是有點繁瑣。如果每次遇到一個列表就要處理這么多,豈不是非常消耗時間?CvL28資訊網——每日最新資訊28at.com

因此我們這里考慮將這些邏輯統一封裝到 List 組件里,下次要使用直接拿出來用就可以了。CvL28資訊網——每日最新資訊28at.com

// ./List/index.tsxexport default function List(props) {}

在封裝時,我們首先要考慮哪些屬性需要作為 props 傳入該 List 組件。關于封裝的思考,和其他的邏輯封裝是一樣的,我們需要先考慮在不同的場景之下,他們的共性與差異分別是什么,差異的部分作為參數傳入。CvL28資訊網——每日最新資訊28at.com

三個數據,error,loading,list 都是差異部分,他們需要作為 props 傳入。CvL28資訊網——每日最新資訊28at.com

先定義一個類型聲明如下:CvL28資訊網——每日最新資訊28at.com

interface ListProps<T> {  loading?: boolean,  error?: string,  list?: T[]}

此時我們看到由于 list 的每一項具體數據內容,可能每一個列表都不一樣,我們無法在這里確認他的類型,因此此處使用泛型來表示。CvL28資訊網——每日最新資訊28at.com

不知道 list 的每一項具體數據是什么,也就意味著對應的 UI 我們也無法提前得知,只有在使用時才知道,因此還應該補上一個新的 props 屬性。CvL28資訊網——每日最新資訊28at.com

interface ListProps<T> {  loading?: boolean,  error?: string,  list?: T[],+ renderItem: (item: T) => ReactNode}

然后我們只需要把差異部分與共同部分在組件邏輯中組合起來即可,List 組件完整代碼如下:CvL28資訊網——每日最新資訊28at.com

import Icon from 'components/Icon'import { ReactNode } from 'react'import s from './index.module.scss'interface ListProps<T> {  loading?: boolean,  error?: string,  list?: T[],  renderItem: (item: T) => ReactNode}export default function List<T>(props: ListProps<T>) {  const {list = [], loading, error, renderItem} = props  if (error) {    return (      <div className={s.wrapper}>        {loading && (          <div className={s.loading_wrapper}>            <Icon spin type='loading' style={{ fontSize: 40 }} />          </div>        )}        <Icon type='event' color='red' style={{ fontSize: 32 }} />        <div className={s.error}>{error}</div>      </div>    )  }  if (list.length === 0) {    return (      <div className={s.wrapper}>        {loading && (          <div className={s.loading_wrapper}>            <Icon spin type='loading' color='#2860Fa' style={{ fontSize: 38 }} />          </div>        )}        <Icon type='event' color='#ccc' style={{ fontSize: 32 }} />        <div className={s.nodata}>暫無數據</div>      </div>    )  }  return (    <div className={s.list}>      {loading && (        <div className={s.loading_wrapper}>          <Icon spin type='loading' color='#2860Fa' style={{ fontSize: 38 }} />        </div>      )}      {list.map(renderItem)}    </div>  )}

封裝好之后,使用起來就非常簡單了,我們只需要把當前上下文中的數據傳入進去即可。CvL28資訊網——每日最新資訊28at.com

<List   list={list}   loading={loading}    error={error}  renderItem={(item) => (    <div key={item} className={s.item}>{item}</div>  )}/>

該案例組件文件路徑:src/pages/demos/effect/search/Normal.tsxCvL28資訊網——每日最新資訊28at.com

四、需求改進

在某些場景,初始化時我們并不需要展示空數組,而是需要請求一次接口,然后展示對應的列表,因此,在這種需求的情況下,代碼需要進行一些調整。CvL28資訊網——每日最新資訊28at.com

首先,Loading 的初始化狀態需要從 false 改為 true,表示一開始就會立即請求數據。CvL28資訊網——每日最新資訊28at.com

- const [loading, setLoading] = useState(false)+ const [loading, setLoading] = useState(true)

然后初始化請求數據的操作,在 useEffect 中完成,傳入空數組作為依賴項,表示只在組件首次渲染完成之后執行一次。CvL28資訊網——每日最新資訊28at.com

... + useEffect(() => {+   searchApi(str.current).then(res => {+     setList(res)+     setLoading(false)+     setError('')+   }).catch(err => {+     setLoading(false)+     setError(err)+   })+ }, [])function onSure() {  setLoading(true)  searchApi(str.current).then(res => {    setList(res)    setLoading(false)    setError('')  }).catch(err => {    setLoading(false)    setError(err)  })}...

OK,這樣需求就完整的被解決,不過此時我們發現,useEffect 的邏輯與 onSure 的邏輯高度重合,他們一個代表初始化邏輯,一個代表更新邏輯。CvL28資訊網——每日最新資訊28at.com

因此在代碼上做一些簡單的調整。CvL28資訊網——每日最新資訊28at.com

function getList() {    searchApi(str.current).then(res => {      setList(res)      setLoading(false)      setError('')    }).catch(err => {      setLoading(false)      setError(err)    })  }  useEffect(() => {    getList()  }, [])  function onSure() {    setLoading(true)    getList()  }

這樣調整了之后,我們發現一個有趣的事情,當點擊搜索按鈕觸發 onSure 時,我們會執行一次把 loading 修改為 true 的操作。CvL28資訊網——每日最新資訊28at.com

setLoading(true)

那如果這個時候,我們就可以把 loading 作為 useEffect 的依賴項傳入,onSure 里就可以只保留這一行代碼。CvL28資訊網——每日最新資訊28at.com

useEffect(() => {  loading && getList()}, [loading])function onSure() {  setLoading(true)}

這就是我們在本書唯一付費章節「React 哲學」中提到的開關思維。在日常生活中,如果我想要打開電視機,我們只需要關注開關按鈕那一下操作,在這里也是一樣,如果我想要重新請求列表搜索,我只需要關注如何操作 loading 這個開關即可CvL28資訊網——每日最新資訊28at.com

該案例組件文件路徑:src/pages/demos/effect/search/Normal2.tsx。CvL28資訊網——每日最新資訊28at.com

接下來我們將要學習自定義 hook,進一步感受開關思維的魅力。CvL28資訊網——每日最新資訊28at.com

本文鏈接:http://www.www897cc.com/showinfo-26-35286-0.htmluseEffect 實踐案例之一

聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com

上一篇: 一篇學會用 KEDA 根據工作負載進行快速擴容

下一篇: 消息隊列備選架構選擇,你選擇哪個?

標簽:
  • 熱門焦點
  • Find N3入網:最高支持16+1TB

    OPPO將于近期登場的Find N3折疊屏目前已經正式入網,型號為PHN110。本次Find N3在外觀方面相比前兩代有很大的變化,不再是小號的橫向折疊屏,而是跟別的廠商一樣采用了較為常見的
  • 小米平板5 Pro 12.4簡評:多專多能 兼顧影音娛樂的大屏利器

    疫情帶來了網課,網課盤活了安卓平板,安卓平板市場雖然中途停滯了幾年,但好的一點就是停滯的這幾年行業又有了新的發展方向,例如超窄邊框、高刷新率、多攝鏡頭組合等,這就讓安卓
  • 從 Pulsar Client 的原理到它的監控面板

    背景前段時間業務團隊偶爾會碰到一些 Pulsar 使用的問題,比如消息阻塞不消費了、生產者消息發送緩慢等各種問題。雖然我們有個監控頁面可以根據 topic 維度查看他的發送狀態,
  • 這款新興工具平臺,讓你的電腦效率翻倍

    隨著信息技術的發展,我們獲取信息的渠道越來越多,但是處理信息的效率卻成為一個瓶頸。于是各種工具應運而生,都在爭相解決我們的工作效率問題。今天我要給大家介紹一款效率
  • 三分鐘白話RocketMQ系列—— 如何發送消息

    我們知道RocketMQ主要分為消息 生產、存儲(消息堆積)、消費 三大塊領域。那接下來,我們白話一下,RocketMQ是如何發送消息的,揭秘消息生產全過程。注意,如果白話中不小心提到相關代
  • 大廠卷向扁平化

    來源:新熵作者丨南枝 編輯丨月見大廠職級不香了。俗話說,兵無常勢,水無常形,互聯網企業調整職級體系并不稀奇。7月13日,淘寶天貓集團啟動了近年來最大的人力制度改革,目前已形成一
  • iQOO 11S或7月上市:搭載“雞血版”驍龍8Gen2 史上最強5G Soc

    去年底,iQOO推出了“電競旗艦”iQOO 11系列,作為一款性能強機,iQOO 11不僅全球首發2K 144Hz E6全感屏,搭載了第二代驍龍8平臺及144Hz電競屏,同時在快充
  • iQOO Neo8 Pro搶先上架:首發天璣9200+ 安卓性能之王

    經過了一段時間的密集爆料,昨日iQOO官方如期對外宣布:將于5月23日推出全新的iQOO Neo8系列新品,官方稱這是一款擁有旗艦級性能調校的作品。隨著發布時
  • 由于成本持續增加,筆記本產品價格預計將明顯上漲

    根據知情人士透露,由于材料、物流等成本持續增加,筆記本產品價格預計將在2021年下半年有明顯上漲。進入6月下旬以來,全球半導體芯片缺貨情況加劇,顯卡、處理器
Top 主站蜘蛛池模板: 峨眉山市| 鞍山市| 定日县| 嫩江县| 休宁县| 岳普湖县| 甘南县| 邵阳县| 罗田县| 郁南县| 龙里县| 旺苍县| 安阳市| 西安市| 堆龙德庆县| 九龙城区| 璧山县| 怀仁县| 馆陶县| 舞钢市| 广河县| 商河县| 东方市| 安新县| 黄梅县| 普宁市| 丹寨县| 富平县| 双牌县| 佛坪县| 中卫市| 淅川县| 娱乐| 丰原市| 班玛县| 宕昌县| 盐源县| 类乌齐县| 甘孜县| 徐闻县| 阜新市|