欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

ReactQuery系列React?Query?實踐示例詳解

 更新時間:2022年11月10日 11:33:15   作者:lakb248  
這篇文章主要為大家介紹了ReactQuery系列React?Query?實踐示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

引言

當2018年GraphQL特別是Apolllo Client開始流行之后,很多人開始認為它將替代Redux,關于Redux是否已經(jīng)落伍的問題經(jīng)常被問到。

我很清晰地記得我當時對這些觀點的不理解。為什么一些數(shù)據(jù)請求的庫會替代全局狀態(tài)管理庫呢?這兩者有什么關聯(lián)呢?

曾經(jīng)我認為像Apollo這樣的Graphql客戶端只能用來請求數(shù)據(jù),就像axios一樣,你仍然需要一些方式來讓請求的數(shù)據(jù)可以被應用程序訪問到。

我發(fā)現(xiàn)我大錯特錯。

客戶端狀態(tài) vs 服務端狀態(tài)

Apollo提供的不僅僅是描述所需數(shù)據(jù)同時獲取數(shù)據(jù)的能力,它同時提供了針對這些服務端數(shù)據(jù)的緩存能力。這意味著你可以在多個組件中使用相同的useQueryhook,它只會觸發(fā)一次數(shù)據(jù)請求并且按照請求的先后順序返回緩存中的數(shù)據(jù)。

這看起來跟我們(包括很多除了我們以外的團隊)在一些場景使用redux的目的很相似:從服務器獲取數(shù)據(jù),然后讓這部分數(shù)據(jù)可以在所有地方可以被訪問到。

所以似乎我們經(jīng)常將這些服務端數(shù)據(jù)當成客戶端狀態(tài)來看待,除了這些服務端數(shù)據(jù)(比如:一個文章列表,你需要顯示的某個用戶的詳細信息,...),你的應用并不真正擁有它。我們只是借用了最新版本的一份數(shù)據(jù)然后展示給用戶。服務端才真正擁有這部分數(shù)據(jù)。

對于我來說,這給了我一個如何看待數(shù)據(jù)的新的思路。如果我們能利用緩存來顯示我們不擁有的那部分數(shù)據(jù),那么剩下的應用需要處理的真正的客戶端狀態(tài)將大大減少。這使我理解了為什么很多人認為Apollo可以在很多場景替代redux。

React Query

我一直沒有機會使用GraphQL。我們有現(xiàn)成的REST API,并沒有遇到冗余請求的問題,目前完全溝通。并沒有足夠的理由讓我們轉換到GraphQL,特別是你還需要讓后端服務配合進行改動。
但是我還是羨慕GraphQL帶來的前端數(shù)據(jù)請求(包括loading和錯誤態(tài)的處理)的簡潔。如果React生態(tài)中有相似的針對REST API的方案就好了。

讓我們來看看React Query吧。

Tanner Linsley在2019年開發(fā)的React Query使得在REST API中也可以使用到Apollo所帶來的好處。他支持任何返回Promise的函數(shù)并且使用了stale-while-revalidate緩存策略。庫本身有一些默認行為可以盡可能保證數(shù)據(jù)的實時性,同時盡可能快的將數(shù)據(jù)返回給用戶,讓人們感覺近乎實時的體驗以提供優(yōu)秀的用戶體驗。在這之上,他同時提供了靈活的自定義能力來滿足各種場景。

這篇文章并不會對React Query進行詳細的介紹。

我認為官方文檔已經(jīng)對使用和概念進行了很好的介紹,同時也有很多關于這方面的視頻,并且Tanner開了一門課程可以讓你熟悉這個庫。

我將會更多的關注在官方文檔之外的一些實踐上的介紹,當你已經(jīng)使用這個庫一段時間之后,也許這些介紹對你會有所幫助。這其中有一些我過去幾個月在深度使用React Query以及從React Query社區(qū)中總結出的經(jīng)驗。

關于默認行為的解釋

我相信React Query的默認行為是經(jīng)過深思熟慮的,但是他們有時會讓你措手不及,特別是剛開始使用的時候。

首先,React Query并不會在每次render的時候都執(zhí)行queryFn,即使默認的staleTime是0。你的應用在任何時候可能會因為各種原因重新render,所以如果每次都fetch是瘋狂的!
如果你看到了一個你不希望的refetch,這很可能是因為你剛聚焦了當前窗口同時React Query執(zhí)行了refetchOnWindowFocus,這在生產(chǎn)環(huán)境是一個很棒的特性:如果用戶在不同的瀏覽器tab之間切換,然后回到了你的應用,一個后臺的refetch會被自動觸發(fā),如果在同一個時間服務端數(shù)據(jù)發(fā)生了變更,那屏幕上的數(shù)據(jù)會被更新。所有這些會在看不到loading態(tài)的情況下發(fā)生,如果數(shù)據(jù)和緩存中的數(shù)據(jù)對比沒有變化的話,你的組件不會進行重新render。

在開發(fā)階段,這個現(xiàn)象會出現(xiàn)得更加頻繁,特別是當你在瀏覽器DevTools和你的應用之間切換的時候。

其次,cacheTimestaleTime的區(qū)別似乎經(jīng)常讓人感到困惑,所以讓我來說明一下:

  • StaleTime:一個查詢變成失效之前的時長。如果查詢是有效的,那么查詢就會一直使用緩存中的數(shù)據(jù),不會進行網(wǎng)絡請求。如果查詢是處于失效狀態(tài)(默認情況下查詢會立即失效),首先仍然會從緩存中獲取數(shù)據(jù),但是同時后臺在滿足一定條件的情況下會發(fā)起一次查詢請求。
  • CacheTime:查詢從變成非激活態(tài)到從緩存中移除持續(xù)的時長。默認是五分鐘,當沒有注冊的觀察者的時候,查詢會變成非激活態(tài),所以如果所有使用了某個查詢的組件都銷毀的時候,這個查詢就變成了非激活態(tài)。
    大多數(shù)情況下,如果你要改變這兩個設置其中的某一個的話,大部分情況下應該修改staleTime。我很少會需要修改cacheTime。在文檔里面也有一個關于這個的解釋。

使用React Query DevTools

DevTools會幫助你更好的理解查詢中的狀態(tài)。它會告訴你當前緩存中的數(shù)據(jù)是什么,所以你可以更方便的進行調試。除了這些,我發(fā)現(xiàn)在DevTools中可以模擬你的網(wǎng)絡環(huán)境來更直觀的看到后臺refetch,因為本地服務一般都很快。

把query key理解成一個依賴列表

我這里所說的依賴列表是類比useEffect中說到的依賴列表,我假設你已經(jīng)對useEffect已經(jīng)比較熟悉了。

為什么這兩者會是相似的呢?

因為React Query會觸發(fā)refetch當query key發(fā)生變化。所以當我們給queryFn傳了一個變量的時候,大部分情況下我們都是希望當這個變量發(fā)生變化的時候可以請求數(shù)據(jù)。相比于通過復雜的代碼邏輯來手動觸發(fā)一個refetch,我們可以利用query key:

type State = 'all' | 'open' | 'done'
type Todo = {
  id: number
  state: State
}
type Todos = ReadonlyArray<Todo>
const fetchTodos = async (state: State): Promise<Todos> => {
  const response = await axios.get(`todos/${state}`)
  return response.data
}
export const useTodosQuery = (state: State) =>
  useQuery(['todos', state], () => fetchTodos(state))

這里,想象我們的UI顯示了一個帶有過濾器的todo列表。我們會有一些本地狀態(tài)來存儲過濾器的數(shù)據(jù),當用戶改變了過濾條件之后,我們會更新本地的狀態(tài),然后React Query會自動觸發(fā)一個refetch,因為query key發(fā)生了變化。我們最終實現(xiàn)了過濾狀態(tài)和查詢函數(shù)的同步,這與useEffect中的依賴列表很相似。我從來沒有沒有出現(xiàn)過給queryFn傳了一個變量,但是這個變量不是queryKey的一部分的情況。

一個新的緩存入口

因為query key被用作緩存的key,所以當你把狀態(tài)從all改成done的時候,你會得到一個新的緩存入口,當你第一次切換過濾狀態(tài)的時候,會導致一個強制的loading狀態(tài)(很可能會限制一個loading動畫)。這當然不是最理想的,所以你可以使用keepPreviousData來處理這種情況,或者你可以使用initialData來為新的緩存入口預填充數(shù)據(jù)。上面那個例子可以很完美的解釋這個情況,因為我們可以做一些客戶端的數(shù)據(jù)預過濾:

type State = 'all' | 'open' | 'done'
type Todo = {
  id: number
  state: State
}
type Todos = ReadonlyArray<Todo>
const fetchTodos = async (state: State): Promise<Todos> => {
  const response = await axios.get(`todos/${state}`)
  return response.data
}
export const useTodosQuery = (state: State) =>
  useQuery(['todos', state], () => fetchTodos(state), {
    initialData: () => {
      const allTodos = queryClient.getQueryData<Todos>(['todos', 'all'])
      const filteredData =
        allTodos?.filter((todo) => todo.state === state) ?? []
      return filteredData.length > 0 ? filteredData : undefined
    },
  })

現(xiàn)在,每次用戶切換過濾條件的時候,如果我們沒有數(shù)據(jù),我們會嘗試用'all todos'緩存中的數(shù)據(jù)來預填充。我們可以馬上就顯示'done'的todo給用戶,他們可以在后臺fetch結束之后看到更新之后的列表。注意v3版本中,你需要設置initialStale屬性來觸發(fā)一個后臺fetch。
我認為這簡單的幾行代碼可以給你帶來很好的用戶體驗的提升。

把服務端狀態(tài)和客戶端狀態(tài)分開

這個觀點和我上個月寫的文檔一樣:如果你從useQuery中拿到了數(shù)據(jù),不要把這部分數(shù)據(jù)放到本地狀態(tài)中。主要的原因是這樣會使得React Query所有后臺更新失效,因為復制出來的本地狀態(tài)不會自動更新。
如果你希望獲取一些默認數(shù)據(jù)來設置一個表單的默認值,然后使用數(shù)據(jù)來渲染表單,那是可以的。后臺更新并不會因為表單已經(jīng)初始化就忽略之后更新的數(shù)據(jù)。所以如果你想打到這個目的,確保通過設置staleTime來避免觸發(fā)不必要的后臺refetch:

const App = () => {
  const { data } = useQuery('key', queryFn, { staleTime: Infinity })
  return data ? <MyForm initialData={data} /> : null
}
const MyForm = ({ initialData} ) => {
  const [data, setData] = React.useState(initialData)
  ...
}

enabled屬性是很強大的

useQuery hook有很多屬性可以用來自定義他的行為,enabled屬性是很強大的一個,它可以讓你做很多有意思的事情。下面是一些我們可以利用它來實現(xiàn)的功能:

在一個查詢中獲取數(shù)據(jù),然后第二個查詢只有當我們成功的從上一個查詢中獲取數(shù)據(jù)的時候才會觸發(fā)

  • 開啟/關閉查詢

假設我們有一個定時查詢,通過refetchInterval來實現(xiàn),但是當一個彈窗打開的時候我們可以暫停這個查詢,避免彈窗后面的內容發(fā)生變更。

  • 等待用戶輸入

比如我們有一些過濾條件作為query key,但是當用戶還沒進行過濾操作的時候可以不進行查詢。

不要把queryCache當成本地狀態(tài)管理器

如果你要修改queryCache,它應該只發(fā)生在樂觀更新或者在變更之后拿到后臺返回的新數(shù)據(jù)的時候。記住任何一個后臺refetch都會覆蓋這些數(shù)據(jù),所以可以使用其他本地狀態(tài)管理庫

創(chuàng)建自定義hook

即使你只是封裝一個useQuery調用,創(chuàng)建一個自定義hook通常情況下也是值得的,因為:

  • 你可以把真實的數(shù)據(jù)獲取邏輯和UI分離,當時把它和useQuery調用封裝在一起
  • 你可以把對于某個query key的使用都放在同一個文件里面
  • 如果你需要修改一些設置或者增加一些數(shù)據(jù)轉換邏輯,你可以在一個地方進行
    在上面的todo例子里面已經(jīng)有一些使用場景。

我希望這些實踐經(jīng)驗可以幫助你熟悉React Query,更多關于React Query 實踐的資料請關注腳本之家其它相關文章!

相關文章

  • react實現(xiàn)數(shù)據(jù)監(jiān)聽方式

    react實現(xiàn)數(shù)據(jù)監(jiān)聽方式

    這篇文章主要介紹了react實現(xiàn)數(shù)據(jù)監(jiān)聽方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-08-08
  • Rust中Trait的使用

    Rust中Trait的使用

    在Rust中,Trait是一個核心概念,它允許我們定義類型應該具有的行為,本文就來具體介紹一下Rust中Trait的使用,感興趣的可以了解一下,感興趣可以了解一下
    2024-03-03
  • React關于antd table中select的設值更新問題

    React關于antd table中select的設值更新問題

    這篇文章主要介紹了React關于antd table中select的設值更新問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-03-03
  • react組件基本用法示例小結

    react組件基本用法示例小結

    這篇文章主要介紹了react組件基本用法,結合實例形式分析了react組件傳值、生命周期、受控組件和非受控組件等相關操作技巧,需要的朋友可以參考下
    2020-04-04
  • react之umi配置國際化語言locale的踩坑記錄

    react之umi配置國際化語言locale的踩坑記錄

    這篇文章主要介紹了react之umi配置國際化語言locale的踩坑記錄,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-02-02
  • 在react-router4中進行代碼拆分的方法(基于webpack)

    在react-router4中進行代碼拆分的方法(基于webpack)

    這篇文章主要介紹了在react-router4中進行代碼拆分的方法(基于webpack),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-03-03
  • React純前端模擬實現(xiàn)登錄鑒權

    React純前端模擬實現(xiàn)登錄鑒權

    這篇文章主要為大家詳細介紹了React純前端模擬實現(xiàn)登錄鑒權的相關知識,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學習一下
    2024-04-04
  • 理解react中受控組件和非受控組件及應用場景

    理解react中受控組件和非受控組件及應用場景

    當涉及到React框架時,了解受控組件和非受控組件是非常重要的概念,本文主要介紹了理解react中受控組件和非受控組件及應用場景,具有一定的參考價值,感興趣的可以了解一下
    2024-01-01
  • React封裝全屏彈框的方法

    React封裝全屏彈框的方法

    這篇文章主要為大家詳細介紹了React封裝全屏彈框的方法,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-08-08
  • React的Props、生命周期詳解

    React的Props、生命周期詳解

    “Props” 是 React 中用于傳遞數(shù)據(jù)給組件的一種機制,通常作為組件的參數(shù)進行傳遞,在 React 中,props 是只讀的,意味著一旦將數(shù)據(jù)傳遞給組件的 props,組件就不能直接修改這些 props 的值,這篇文章主要介紹了React的Props、生命周期,需要的朋友可以參考下
    2024-06-06

最新評論