<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          用react-query解決你一半的狀態(tài)管理問(wèn)題

          共 3044字,需瀏覽 7分鐘

           ·

          2021-02-18 17:29

          按照來(lái)源,前端有兩類「狀態(tài)」需要管理:

          • 用戶交互的中間狀態(tài)

          • 服務(wù)端狀態(tài)

          在陳年的老項(xiàng)目中,通常用Redux、Mobx這樣的「全局狀態(tài)管理方案」無(wú)差別對(duì)待他們。

          事實(shí)上,他們有很大區(qū)別:

          用戶交互的中間狀態(tài)

          比如組件的isLoading、isOpen,這類「狀態(tài)」的特點(diǎn)是:

          • 「同步」的形式更新

          • 「狀態(tài)」完全由前端控制

          • 「狀態(tài)」比較獨(dú)立(不同的組件擁有各自的isLoading

          這類「狀態(tài)」通常保存在組件內(nèi)部。

          當(dāng)「狀態(tài)」需要跨組件層級(jí)傳遞,通常使用Context API

          再大范圍的「狀態(tài)」會(huì)使用Redux這樣的「全局狀態(tài)管理方案」。

          服務(wù)端狀態(tài)

          當(dāng)我們從服務(wù)端請(qǐng)求數(shù)據(jù):

          function?App()?{
          ??const?[data,?updateData]?=?useState(null);
          ??
          ??useEffect(async?()?=>?{
          ????const?data?=?await?axios.get('/api/user');
          ????updateData(data);
          ??},?[])

          ??//?處理data
          }

          返回的數(shù)據(jù)通常作為「狀態(tài)」保存在組件內(nèi)部(如App組件的data狀態(tài))。

          如果是需要復(fù)用的通用「狀態(tài)」,通常將其保存在Redux這樣的「全局狀態(tài)管理方案」中。

          這樣做有2個(gè)壞處:

          1. 需要重復(fù)處理請(qǐng)求中間狀態(tài)

          為了讓App組件健壯,我們還需要處理請(qǐng)求中出錯(cuò)等中間狀態(tài):

          function?App()?{
          ??const?[data,?updateData]?=?useState(null);
          ??const?[isError,?setError]?=?useState(false);
          ??const?[isLoading,?setLoading]?=?useState(false);
          ??
          ??useEffect(async?()?=>?{
          ????setError(false);
          ????setLoading(true);
          ????try?{
          ??????const?data?=?await?axios.get('/api/user');
          ??????updateData(data);
          ????}?catch(e)?{
          ??????setError(true);
          ????}
          ????setLoading(false);
          ??},?[])

          ??//?處理data
          }

          這類通用的中間狀態(tài)處理邏輯可能在不同組件中重復(fù)寫很多次。

          1. 「緩存」的性質(zhì)不同于「狀態(tài)」

          不同于交互的中間狀態(tài),服務(wù)端狀態(tài)更應(yīng)被歸類為「緩存」,他有如下性質(zhì):

          • 通常以「異步」的形式請(qǐng)求、更新

          • 「狀態(tài)」由請(qǐng)求的數(shù)據(jù)源控制,不由前端控制

          • 「狀態(tài)」可以由不同組件共享

          作為可以由不同組件共享的「緩存」,還需要考慮更多問(wèn)題,比如:

          • 緩存失效

          • 緩存更新

          Redux一把梭固然方便。但是,區(qū)別對(duì)待不同類型「狀態(tài)」能讓項(xiàng)目更可控。

          這里,推薦使用React-Query管理服務(wù)端狀態(tài)。

          另一個(gè)可選方案是SWR[1]。你可以從這里[2]看到他們的區(qū)別

          初識(shí)React-Query

          React-Query是一個(gè)基于hooks的數(shù)據(jù)請(qǐng)求庫(kù)。

          我們可以將剛才的例子用React-Query改寫:

          ?import?{?useQuery?}?from?'react-query'
          ?
          ?function?App()?{
          ???const?{data,?isLoading,?isError}?=?useQuery('userData',?()?=>?axios.get('/api/user'));
          ???
          ???if?(isLoading)?{
          ?????return?<div>loadingdiv>;
          ???}
          ???
          ???return?(
          ?????<ul>
          ???????{data.map(user?=>?<li?key={user.id}>{user.name}li>
          )}
          ?????ul>
          ???)
          ?}

          React-Query中的Query指一個(gè)異步請(qǐng)求的數(shù)據(jù)源。

          例子中userData字符串就是這個(gè)query獨(dú)一無(wú)二的key。

          可以看到,React-Query封裝了完整的請(qǐng)求中間狀態(tài)(isLoading、isError...)。

          不僅如此,React-Query還為我們做了如下工作:

          • 多個(gè)組件請(qǐng)求同一個(gè)query時(shí)只發(fā)出一個(gè)請(qǐng)求

          • 緩存數(shù)據(jù)失效/更新策略(判斷緩存合適失效,失效后自動(dòng)請(qǐng)求數(shù)據(jù))

          • 對(duì)失效數(shù)據(jù)垃圾清理

          數(shù)據(jù)的CRUD由2個(gè)hook處理:

          • useQuery處理數(shù)據(jù)的查

          • useMutation處理數(shù)據(jù)的增/刪/改

          在下面的例子中,點(diǎn)擊「創(chuàng)建用戶」按鈕會(huì)發(fā)起創(chuàng)建用戶的post請(qǐng)求:

          ??import?{?useQuery,?queryCache?}?from?'react-query';

          ?function?App()?{
          ???const?{data,?isLoading,?isError}?=?useQuery('userData',?()?=>?axios.get('/api/user'));
          ???//?新增用戶
          ???const?{mutate}?=?useMutation(data?=>?axios.post('/api/user',?data));
          ?
          ???return?(
          ?????<ul>
          ???????{data.map(user?=>?<li?key={user.id}>{user.name}li>
          )}
          ???????<button
          ?????????onClick={()?=>
          ?{
          ???????????mutate({name:?'kasong',?age:?99})
          ?????????}}
          ???????>
          ?????????創(chuàng)建用戶
          ???????button>
          ?????ul>
          ???)
          ?}

          但是點(diǎn)擊后userData query對(duì)應(yīng)數(shù)據(jù)不會(huì)更新,因?yàn)樗€未失效。

          所以我們需要告訴React-Query,userData query對(duì)應(yīng)的緩存已經(jīng)失效,需要更新:

          import?{?useQuery,?queryCache?}?from?'react-query';

          function?App()?{
          ??//?...
          ??const?{mutate}?=?useMutation(userData?=>?axios.post('/api/user',?userData),?{
          ????onSuccess:?()?=>?{
          ??????queryCache.invalidateQueries('userData')
          ????}??
          ??})
          ??
          ??//?...
          }

          通過(guò)調(diào)用mutate方法,會(huì)觸發(fā)請(qǐng)求。

          當(dāng)請(qǐng)求成功后,會(huì)觸發(fā)onSuccess回調(diào),回調(diào)中調(diào)用queryCache.invalidateQueries,將userData對(duì)應(yīng)的query緩存置為invalidate。

          這樣,React-Query就會(huì)重新請(qǐng)求userData對(duì)應(yīng)query的數(shù)據(jù)。

          總結(jié)

          通過(guò)使用React-Query(或SWR)這樣的數(shù)據(jù)請(qǐng)求庫(kù),可以將服務(wù)端狀態(tài)從全局狀態(tài)中解放出來(lái)。

          這為我們帶來(lái)很多好處:

          • 使用通用的hook處理請(qǐng)求中間狀態(tài)

          • 多余請(qǐng)求合并

          • 針對(duì)緩存的更新/失效策略

          • Redux「全局狀態(tài)管理方案」可以更專注于「前端中間狀態(tài)」處理

          參考資料

          [1]

          SWR: https://swr.vercel.app/

          [2]

          這里: https://react-query.tanstack.com/comparison




          瀏覽 140
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  欧美一级乱码 | 青青草大香蕉视频 | 黄片99| 国产乱婬AAAA片视频软件 | 久久精品国产亚洲AV苍井空 |