日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關咨詢
選擇下列產(chǎn)品馬上在線溝通
服務時間:8:30-17:00
你可能遇到了下面的問題
關閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
如何實現(xiàn)React中的狀態(tài)自動保存?

什么是狀態(tài)保存?

假設有下述場景:

移動端中,用戶訪問了一個列表頁,上拉瀏覽列表頁的過程中,隨著滾動高度逐漸增加,數(shù)據(jù)也將采用觸底分頁加載的形式逐步增加,列表頁瀏覽到某個位置,用戶看到了感興趣的項目,點擊查看其詳情,進入詳情頁,從詳情頁退回列表頁時,需要停留在離開列表頁時的瀏覽位置上

類似的數(shù)據(jù)或場景還有已填寫但未提交的表單、管理系統(tǒng)中可切換和可關閉的功能標簽等,這類數(shù)據(jù)隨著用戶交互逐漸變化或增長,這里理解為狀態(tài),在交互過程中,因為某些原因需要臨時離開交互場景,則需要對狀態(tài)進行保存

在 React 中,我們通常會使用路由去管理不同的頁面,而在切換頁面時,路由將會卸載掉未匹配的頁面組件,所以上述列表頁例子中,當用戶從詳情頁退回列表頁時,會回到列表頁頂部,因為列表頁組件被路由卸載后重建了,狀態(tài)被丟失

如何實現(xiàn) React 中的狀態(tài)保存

在 Vue 中,我們可以非常便捷地通過 [1] 標簽實現(xiàn)狀態(tài)的保存,該標簽會緩存不活動的組件實例,而不是銷毀它們

而在 React 中并沒有這個功能,曾經(jīng)有人在官方提過功能 issues[2] ,但官方認為這個功能容易造成內(nèi)存泄露,表示暫時不考慮支持,所以我們需要自己想辦法了

常見的解決方式:手動保存狀態(tài)

手動保存狀態(tài),是比較常見的解決方式,可以配合 React 組件的 componentWillUnmount 生命周期通過 redux 之類的狀態(tài)管理層對數(shù)據(jù)進行保存,通過 componentDidMount 周期進行數(shù)據(jù)恢復

在需要保存的狀態(tài)較少時,這種方式可以比較快地實現(xiàn)我們所需功能,但在數(shù)據(jù)量大或者情況多變時,手動保存狀態(tài)就會變成一件麻煩事了

作為程序員,當然是盡可能懶啦,為了不需要每次都關心如何對數(shù)據(jù)進行保存恢復,我們需要研究如何自動保存狀態(tài)

通過路由實現(xiàn)自動狀態(tài)保存(通常使用 react-router)

既然 React 中狀態(tài)的丟失是由于路由切換時卸載了組件引起的,那可以嘗試從路由機制上去入手,改變路由對組件的渲染行為

我們有以下的方式去實現(xiàn)這個功能

    1.  重寫 組件,可參考 react-live-route[4]

    重寫可以實現(xiàn)我們想要的功能,但成本也比較高,需要注意對原始 功能的保存,以及多個 react-router 版本的兼容

    2.  替換路由庫為 react-keeper[5]

    完全替換掉路由方案是一個風險較大的事情,需要較為慎重地考慮3.

    3.  基于 組件現(xiàn)有行為做拓展,可參考 react-router-cache-route[6]

    在閱讀了 的源碼后發(fā)現(xiàn),如果使用 component 或者 render 屬性,都無法避免路由在不匹配時被卸載掉的命運

    但將 children 屬性當作方法來使用,我們就有手動控制渲染的行為的可能,關鍵代碼在此處 https://github.com/ReactTraining/react-router/blob/master/packages/react-router/modules/Route.js#L41-L72

 
 
 
 
  1. // 節(jié)選自 Route 組件中的 render 函數(shù)  
  2. if (typeof children === "function") {  
  3.      childrenchildren = children(props); // children 是函數(shù)時,將對 children 進行調(diào)用得到真實的渲染結(jié)果  
  4. if (children === undefined) {  
  5.        ...  
  6.        children = null;  
  7.      }  
  8.    }  
  9. return (  
  10.   
  11.        {children && !isEmptyChildren(children) // children 存在時,將使用 children 進行渲染  
  12.          ? children  
  13.          : props.match  
  14.            ? component  
  15.              ? React.createElement(component, props)  
  16.              : render  
  17.                ? render(props)  
  18.                : null // 使用 render 屬性無法阻止組件的卸載  
  19.            : null // 使用 component 屬性無法阻止組件的卸載  
  20.        }  
  21.   
  22.    ); 

基于上述源碼探究,我們可以對 進行拓展,將 的不匹配行為由卸載調(diào)整為隱藏,如下 

 
 
 
 
  1.   
  2.      {props => (  
  3.            
  4.                
  5.          
  
  •      )}  
  •   
  • 上述是最簡的調(diào)整方式,實際情況中也需要考慮隱藏狀態(tài)下 match 為 null 導致組件報錯的問題,且由于不再是組件卸載,所以和 TransitionGroup 配合得不好,導致轉(zhuǎn)場動畫難以實現(xiàn)

    使用 react-router-cache-route[7],得到的效果大致如下圖,

    上述探究了通過路由入手實現(xiàn)自動狀態(tài)保存的可能,以及現(xiàn)有的實現(xiàn),但終究不是真實的、純粹的 KeepAlive 功能,接下來我們嘗試探究真實 KeepAlive 功能的實現(xiàn)

    模擬真實的 功能

    以下是期望的使用方式

     
     
     
     
    1. function App() {  
    2. const [show, setShow] = useState(true)  
    3. return (  
    4.   
    5.  setShow(show => !show)}>Toggle  
    6.       {show && (  
    7.   
    8.   
    9.   
    10.       )}  
      
  •   )  
  • 實現(xiàn)原理說起來較為簡單,由于 React 會卸載掉處于固有組件層級內(nèi)的組件,所以我們需要將 中的組件,也就是其 children 屬性抽取出來,渲染到一個不會被卸載的組件內(nèi),就可以實現(xiàn)此功能

    以下是 react-activation[8] 的實現(xiàn)效果

    在線示例[9]

    實際實現(xiàn)過程中,遇到了許多問題,都是由于打破了原有 React 層級關系引起的,例如

    •  渲染延遲
    •  Provider 上下文功能失效
    •  Error Boundaries 失效
    •  React.Suspense & React.lazy 失效
    •  React 合成事件冒泡失效
    •  其他未發(fā)現(xiàn)的功能

    但上述問題,大多數(shù)是可以通過橋接機制修復的

    相同的、更早的實現(xiàn)還有 react-keep-alive[10] 

    結(jié)語

    狀態(tài)緩存是應用中十分常見的需求,在需要處理的數(shù)據(jù)量較少時,使用手動狀態(tài)緩存就可以解決大多數(shù)問題,但當情況復雜時,還需要嘗試將緩存功能單獨拎出來解決,以便在業(yè)務開發(fā)過程中更好地進行關注點分離

    目前的實現(xiàn)都有各自的問題,但其探究過程十分有趣,最好的方式仍是官方的支持,但目前還不能報太大期望


    本文標題:如何實現(xiàn)React中的狀態(tài)自動保存?
    瀏覽路徑:http://www.5511xx.com/article/coccidd.html