react-activation 組件級緩存解決方案

文章目錄

  • 一、KeepAlive 組件
  • 二、AliveScope 容器
  • 三、useAliveController Hook
  • 四、生命周期
  • 五、完整示例

react-activation 主要解決 React 項目中的「頁面緩存」需求(是第三方庫,非React 官方),類似于 Vue 中的 <KeepAlive>

功能說明
<KeepAlive> 組件緩存組件 DOM,不卸載
<AliveScope> 容器緩存容器,必須包裹在外層
useAliveController Hook提供緩存管理 API(如 droprefresh
useActivate / useUnactivate 生命周期激活與失活鉤子
  • 地址:GitHub 倉庫

  • NPM:https://www.npmjs.com/package/react-activation

  • 適配版本:推薦用于 React 16 和 React 17(React 18 存在一些副作用不穩定問題)


一、KeepAlive 組件

<KeepAlive> 是一個高階組件,用于緩存(keep-alive)React 組件的狀態,類似于 Vue 的 ,在組件卸載后保留其狀態和 DOM,提升體驗(例如表單不丟失、滾動位置保留等)。

用于緩存組件的 UI 和狀態,當 <AdminHome /> 頁面切走再回來,狀態不會丟失,組件不會重新掛載。

<KeepAlive id="admin-home"><AdminHome />
</KeepAlive>

基本屬性

屬性類型默認值說明
idstring-緩存唯一標識,必須唯一,一般用 pathname
namestringid可選的緩存名稱(某些緩存操作可以用 name)
whenbooleantrue是否啟用緩存,設為 false 表示不緩存
saveScrollPositionfalse | 'screen' | 'container' | ((node: HTMLElement) => any)false是否保存并恢復頁面的滾動位置:
false(默認):不保存滾動位置
'screen': 保存并恢復頁面(window)滾動位置
'container': 自動尋找最近的滾動容器保存滾動位置
(node) => HTMLElement: 自定義返回要記錄滾動位置的 DOM 元素
autoFreezebooleantrue切換時是否凍結 DOM,節省資源
extraanyundefined附加信息,可在緩存控制器中使用(不常用)

二、AliveScope 容器

<AliveScope>react-activation 提供的作用域容器,用來管理緩存組件的上下文和分組控制。

  • 提供上下文,讓 KeepAlive 可以記錄并復用組件狀態

  • 管理組件緩存生命周期

  • 可用于分組銷毀緩存(配合 dropScope(scopeId))

  1. <AliveScope> 是必須包裹住所有 <KeepAlive> 的組件,否則 KeepAlive 不會起作用。

    如果不包裹 <KeepAlive>,它內部就無法訪問緩存管理上下文:

    • KeepAlive 會直接按普通組件渲染,不會緩存
    • useActivate / useUnactivate 鉤子不會被調用
    • useAliveController() 獲取到的控制器是空的
    <AliveScope name="user-scope"><KeepAlive id="user-list"><UserList /></KeepAlive><KeepAlive id="user-detail"><UserDetail /></KeepAlive>
    </AliveScope>
    

    標準寫法是直接把 <AliveScope> 放在根節點。

    import React from 'react';
    import ReactDOM from 'react-dom';
    import { AliveScope } from 'react-activation';
    import App from './App';ReactDOM.render(<AliveScope><App /></AliveScope>,document.getElementById('root')
    );
    
  2. AliveScope 可選屬性

    屬性類型默認值說明
    namestringdefault作用域唯一標識,可用于區分多個 AliveScope
    includestring[][]允許緩存的組件 ID 列表(白名單)
    excludestring[][]禁止緩存的組件 ID 列表(黑名單)
    maxnumberInfinity緩存數量上限,超過后會自動淘汰最久未使用的(LRU 策略)
    cacheKeystringnamelocalStorage 緩存相關的 key(需要搭配 persist
    persistbooleanfalse是否持久化緩存(刷新頁面或關閉瀏覽器后,再次進入,緩存狀態仍然保留,保存在 localStorage)
    autoClearbooleanfalse是否在頁面刷新后自動清空緩存(防止緩存穿透,防止過時數據)
  3. 配合 KeepAlive 使用

    import { AliveScope, KeepAlive } from 'react-activation';
    import UserList from './UserList';
    import UserDetail from './UserDetail';export default function Root() {return (<AliveScope name="user-scope" include={['user-list']}><KeepAlive id="user-list"><UserList /></KeepAlive><KeepAlive id="user-detail"><UserDetail /></KeepAlive></AliveScope>);
    }
    
    • 只有 user-list 會被緩存(受 include 控制)

    • 可以通過 useAliveController().dropScope('user-scope') 一鍵清除

  4. 多個 AliveScope 的使用方式

    把用戶模塊和管理員模塊的緩存完全隔離開,這樣每個作用域有自己獨立的緩存池

    <!-- 用戶模塊 -->
    <AliveScope name="user-scope"><KeepAlive id="user-list"><UserList /></KeepAlive><KeepAlive id="user-detail"><UserDetail /></KeepAlive>
    </AliveScope><!-- 管理員模塊 -->
    <AliveScope name="admin-scope"><KeepAlive id="admin-home"><AdminHome /></KeepAlive>
    </AliveScope>
    

    這時可以使用 useAliveController() 來獲取緩存控制器,跨作用域控制:

    import { useAliveController } from 'react-activation';export default function ClearButton() {const { dropScope } = useAliveController();return (<><button onClick={() => dropScope('user-scope')}>清空用戶模塊緩存</button><button onClick={() => dropScope('admin-scope')}>清空管理員模塊緩存</button></>);
    }
    
    • dropScope(‘user-scope’) 會銷毀 user-scope 作用域中所有 KeepAlive 緩存

    • 也可以用 refreshScope(name) 強制刷新一個作用域內所有組件


三、useAliveController Hook

這是一個自定義 Hook,提供對緩存組件的控制,比如手動刷新(drop)某個緩存組件、獲取緩存狀態等。

const { drop, dropScope, refresh } = useAliveController();// 單作用域: 卸載某個緩存組件(通過 KeepAlive 的 id)
// 使用場景:點擊“關閉標簽頁”
drop('user-list');  // 卸載 id 為 'user-list' 的 KeepAlive 緩存
drop('user-detail');
// 👉 全部要寫一遍,或維護復雜緩存 id 列表// 多作用域: 卸載該作用域下的所有緩存組件(通過 AliveScope 的 name),比 drop(id) 更高級別的操作
// 使用場景:退出登錄清除所有緩存
dropScope('user-scope'); // 卸載 <AliveScope name="user-scope"> 下的所有 KeepAlive 緩存// 強制刷新(先卸載再重建)
// 使用場景:點擊“重置表單”或“刷新頁面”
refresh('user-list'); // 會先 drop(‘user-list’),然后立刻重新掛載組件
  • dropScope 的參數是 中的 name。

  • 使用前確保這些組件確實是包裹在 <AliveScope> 內的。

  • AliveScope 是 react-activation 中用于分組緩存的容器,必須明確設置 name 才能使用 dropScope。
    .

🔥 在 react-activation 中,組件必須處于「非激活狀態」( 即 KeepAlive 的 when 為 false、或組件被隱藏 ),才允許卸載或刷新。不會立即卸載當前正在顯示的組件

方法作用會立即卸載當前正在顯示的組件嗎?何時真正卸載?
drop(id)刪除某個緩存組件的狀態? 不會立即卸載當前正在顯示的?? 當該組件被切換隱藏時
dropScope(scopeId)刪除整個 AliveScope 中的緩存? 不會立即卸載當前正在顯示的?? 當前組件不顯示后才會銷毀
refresh(id)刪除后重新創建組件? 不會立即刷新當前激活組件?? 必須切到其他組件再切回來才生效
  • drop / dropScope / refresh 不會卸載當前正在顯示的組件

  • 它們只對非激活(未渲染)的組件生效

  • ? 正確的做法是:切換走 → drop → 才生效:

    history.push('/other');
    await drop('/current'); // ? 現在它處于非激活狀態,drop 生效
    

四、生命周期

react-activation(React 第三方庫) 提供的自定義 Hook,模擬 Vue 的 activated / deactivated 生命周期。

<AliveScope><KeepAlive id="user"><UserPage /></KeepAlive>
</AliveScope>import { useActivate, useUnactivate, useAliveEffect } from 'react-activation';// 組件激活時調用(進入或返回該緩存組件時),替代 useEffect 的 didShow
useActivate(() => {console.log('頁面被激活(顯示): 進入時刷新數據')
});// 組件失活時調用(從該組件跳出,但未卸載),類似 componentWillPause
useUnactivate(() => {console.log('頁面被隱藏但未卸載: 退出時保存狀態')
});// 只有當組件是“激活狀態”時,才會執行 useEffect,可以響應 deps 的變化,可替代 useEffect + useActivate 組合
useAliveEffect(() => {const timer = setInterval(() => {console.log('只在激活狀態時輪詢');}, 1000);return () => clearInterval(timer);
}, []);

類似于 Vue3:

<template><KeepAlive include="UserPage"><component :is="currentView" /></KeepAlive>
</template>// 原生生命周期鉤子
onActivated(() => {console.log('組件被緩存激活');
});onDeactivated(() => {console.log('組件被緩存關閉');
});

五、完整示例

? 標簽切換自動緩存
? 點擊關閉標簽頁 → 銷毀對應緩存
? 支持多個 AliveScope 管理模塊分組
? 使用 KeepAlive + useActivate + useUnactivate

  1. main.tsx(注冊多個作用域)

    import React from 'react';
    import ReactDOM from 'react-dom';
    import { AliveScope } from 'react-activation';
    import App from './App';ReactDOM.render(<><AliveScope name="module-user"><App /></AliveScope>{/* 可拓展其他模塊作用域 */}</>,document.getElementById('root')
    );
    
  2. App.tsx(入口,渲染標簽頁)

    import React from 'react';
    import TabView from './components/TabView';export default function App() {return (<div><TabView /></div>);
    }
    
  3. TabView.tsx(核心組件)

    import React, { useState } from 'react';
    import { KeepAlive, useAliveController } from 'react-activation';
    import PageA from './PageA';
    import PageB from './PageB';
    import PageC from './PageC';const tabComponents: Record<string, React.ReactNode> = {A: <PageA />,B: <PageB />,C: <PageC />,
    };const TabView = () => {const [tabs, setTabs] = useState(['A', 'B', 'C']);const [active, setActive] = useState('A');const { drop } = useAliveController();const closeTab = async (key: string) => {// 比如當前 tabs 是 ['A', 'B', 'C'],要關閉 A 標簽setTabs(prev => prev.filter(t => t !== key)); // 更新標簽頁列表(異步),由['A', 'B', 'C'] -> ['B', 'C']if (active === key) { // 如果關閉的是當前激活標簽const other = tabs.find(t => t !== key); // 從標簽頁列表['A', 'B', 'C']中找出第一個非 key 的 tab(即 'B')if (other) setActive(other); // 激活新標簽B}await drop(`page-${key}`); // 卸載對應標簽的緩存組件(卸載'page-A')};return (<div><div style={{ display: 'flex', gap: 8, marginBottom: 12 }}>{tabs.map(tab => (<divkey={tab}style={{padding: '6px 12px',border: active === tab ? '2px solid blue' : '1px solid #ccc',borderRadius: 4,cursor: 'pointer',background: '#f7f7f7',position: 'relative',}}onClick={() => setActive(tab)}>Page {tab}<spanonClick={e => {e.stopPropagation();closeTab(tab);}}style={{marginLeft: 6,color: 'red',cursor: 'pointer',fontWeight: 'bold',}}>×</span></div>))}</div><div style={{ border: '1px solid #ccc', padding: 12 }}>{tabs.map(tab =>active === tab ? (<KeepAlive id={`page-${tab}`} key={tab}>{tabComponents[tab]}</KeepAlive>) : null)}</div></div>);
    };export default TabView;
    
  4. PageA.tsx(緩存與生命周期)

    import React, { useState } from 'react';
    import { useActivate, useUnactivate } from 'react-activation';export default function PageA() {const [count, setCount] = useState(0);useActivate(() => {console.log('PageA 激活');});useUnactivate(() => {console.log('PageA 失活');});return (<div><h2>Page A</h2><p>計數: {count}</p><button onClick={() => setCount(c => c + 1)}>+1</button></div>);
    }
    

    PageB.tsx、PageC.tsx 同上

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/85315.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/85315.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/85315.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

CentOS 7內核升級方案

關于升級 CentOS 7 系統內核至 4.19 版本的可執行升級方案,可根據實際情況進行調整和完善,希望能對大家有所幫助: 一、升級背景與目的 隨著業務的發展和系統穩定性的要求,當前 CentOS 7 系統所使用的內核版本 3.10.0-1160.el7.x86_64 已經無法滿足部分新功能需求以及面臨…

樹莓派實驗實踐記錄與技術分析

一、內核驅動開發&#xff1a;hello 模塊實現 驅動程序代碼 #include <linux/init.h> #include <linux/module.h> static int __init hello_init(void) { printk(KERN_INFO "hello kernel\n"); return 0; } module_init(hello_init); static void …

【秦九紹算法】小紅的 gcd

題目 牛客網&#xff1a;小紅的 gcd 題目分析 我們知道&#xff0c;求gcd就用歐幾里得算法&#xff08;輾轉相除法&#xff09;&#xff1a;gcd(a,b)gcd(b,a mod b)。但是這題的a非常大&#xff0c;最大是一個1e6位數&#xff0c;無法使用任何數據類型存儲。如果使用高精度…

AWS服務監控之EC2內存監控

首先在IAM里找到角色&#xff0c;創建角色&#xff0c;選擇EC2 然后在被監控的機器上安裝cloudwatch-agent 官方鏈接在本地服務器上安裝 CloudWatch 代理 - Amazon CloudWatch wget https://s3.amazonaws.com/amazoncloudwatch-agent/redhat/amd64/latest/amazon-cloudwatch-a…

鴻蒙 ArkWeb 和 H5混編開發

ArkWeb Web 相關標準技術(HTML/CSS/JS)&#xff0c;是業內支持性最廣泛的技術&#xff0c;可以在最廣泛的平臺下實現“一次編寫到處運行”&#xff1b;大部分對性能無需極致要求的應用頁面&#xff0c;都可以使用 Web 技術來實現。 鴻蒙 ArkWeb Kit&#xff08;方舟 Web&…

設計模式-迪米特法則(Law of Demeter, LoD)

迪米特法則&#xff08;Law of Demeter, LoD&#xff09; 別名&#xff1a;最少知識原則&#xff08;Least Knowledge Principle&#xff09; 核心思想&#xff1a;一個對象應盡可能少地與其他對象發生交互&#xff0c;只與直接的朋友&#xff08;成員變量、方法參數、方法返回…

python獲取AB直線間任意一點經緯度

獲取AB直線間任意一點經緯度 1、目標 已知A點經緯度,距離;B點經緯度,距離,如果C點在AB之間,且知道C點距離,求C點的經緯度信息。 目標:在AB這條直線上,根據給定的距離(從A點開始沿直線到某點的距離)來求該點的經緯度。 2、方法 首先計算AB的總長度(大圓距離),…

Android實戰——系統字體庫加載流程

Android 系統字體庫指的是在Android設備上用于顯示文本的字體集合。隨著Android系統的更新,其對字體的支持也日益增強,允許開發者和用戶更靈活地定制界面文字顯示。 一、字體庫介紹 1、字體庫文件 字體庫文件是指存儲字體數據的文件,這些文件包含了創建文本字符所需的所有…

嵌入式樂鑫音頻項目“無聲”問題深度調試復盤與方法論總結

前言&#xff1a;一場典型的“工程師尋蹤之旅” 本次調試始于一個看似簡單卻極其頑固的問題&#xff1a;在一個基于樂鑫ESP-ADF&#xff08;音頻開發框架&#xff09;的DuerOS示例項目中&#xff0c;移植到M5Stack ATOMIC Echo Base硬件上后&#xff0c;程序能夠成功編譯、燒錄…

地下安全防線:電纜通道防外破地釘如何守護城市隱形生命線

在繁華都市的柏油馬路之下、在靜謐鄉村的泥土深處&#xff0c;縱橫交錯的地下管線如同城市與鄉村的 “隱形生命線”&#xff0c;承載著電力輸送、供水供氣、通信傳輸等重要功能&#xff0c;默默維系著現代社會的正常運轉。然而&#xff0c;這條 “生命線” 正面臨著諸多潛在威脅…

linux時間同步方案

yum install chrony -y # 配置 chrony 使用國內服務器 sed -i s/^pool.*pool.ntp.org/#&/ /etc/chrony.conf cat >> /etc/chrony.conf <<EOF server ntp.aliyun.com iburst server ntp.tencent.com iburst server ntp.ntsc.ac.cn iburst server time1.cloud.t…

C語言筆記(鵬哥)上課板書+課件匯總(KMP算法的動態規劃簡易處理+字符函數和字符串函數)

一、目錄 kmp動態規劃簡易處理next數組字符函數與字符串函數 一、目錄二、引言C語?標準庫中提供了?系列庫函數 三、字符分類函數&#xff08;字符相關的函數&#xff09;推薦一個網站 四、字符轉換函數&#xff08;字符相關的函數&#xff09;五、strlen&#xff08;字符串相…

Java大模型開發入門 (13/15):擁抱官方標準 - Spring AI框架入門與實踐

前言 到目前為止&#xff0c;我們整個系列的旅程都是在功能強大的LangChain4j框架上構建的。它就像一個裝備齊全的“瑞士軍刀”&#xff0c;為我們提供了構建RAG和Agents所需的所有底層和高層工具。 然而&#xff0c;在Java企業級開發的世界里&#xff0c;有一個名字我們永遠…

Github搜索案例

今天的內容是這個案例的實現&#xff0c;以及其中涉及到的內容&#xff0c;需要全部掌握&#xff0c;比如ref&#xff0c;受控組件&#xff0c;props在組件之中的傳遞&#xff0c;以及Pubsub包的使用這些前端React框架有關的內容。現在進入正題 1.github搜索案例&#xff08;a…

Vue3學習(生命周期,hooks,axios的簡單講解)

一&#xff0c;前言 繼續努力&#xff0c;南方見。 二&#xff0c;生命周期 1.對生命周期的理解 例如&#xff1a;人的生命周期&#xff0c;出生&#xff0c;經歷&#xff0c;死亡 組件的話就是&#xff0c;創建&#xff0c;掛載&#xff0c;更新&#xff0c;銷毀。***在特…

Pytorch實戰四 基于 VGG net 搭建一個串聯的神經網絡結構

系列文章目錄 文章目錄 系列文章目錄前言一、VGG類的搭建1.源碼2.初始化類2.1 初始化函數2.2 前向傳播函數 forward(self,x) 二、卷積補充卷積 前言 對于標準的 VGG net 輸入圖像的尺寸是 24 x 24,進行 32 維的下采樣之后得到一個 7 x 7 的特征圖&#xff0c;然后用 FC 層完成分…

大學專業解讀——計算機

我們繼續&#xff0c;講講排名第二流行的新工科專業——計算機。說到計算機&#xff0c;可能所有人都知道&#xff0c;但具體到細分的專業類別&#xff0c;除了計算機科學&#xff0c;其實大多數人都是不了解的。 序&#xff1a; 計算機主要有如下幾個專業&#xff1a; 計算機…

Bootstrap 5學習教程,從入門到精通, Bootstrap 5 列表組(List Group)語法知識點及案例(14)

Bootstrap 5 列表組(List Group)語法知識點及案例 一、列表組基礎語法 列表組是Bootstrap中用于顯示一系列內容的靈活組件&#xff0c;常用于顯示菜單、導航或任何項目列表。 基本列表組結構 <ul class"list-group"><li class"list-group-item&quo…

FPGA基礎 -- Verilog 命名事件

Verilog 的“命名事件&#xff08;Named Events&#xff09;”機制 進行一次系統、專業的培訓。該機制在 Verilog 中是比較冷門但重要的仿真控制特性&#xff0c;主要用于 模塊間同步、行為仿真觸發、事件通信&#xff0c;在復雜的 Testbench、行為模型中尤為重要。 一、命名事…

《Go語言圣經》結構體

《Go語言圣經》結構體 一、結構體指針的高效應用 在處理大型結構體時&#xff0c;為避免內存復制&#xff0c;通常使用指針傳遞和返回結構體&#xff1a; // 通過指針傳入結構體&#xff0c;避免值拷貝 func Bonus(e *Employee, percent int) int {return e.Salary * percen…