React手把手帶你實現(xiàn)Keep-Alive效果的三種方法
前言
在 Vue 中,我們可以通過 <keep-alive> 輕松緩存組件實例。但在 React 中,組件卸載(Unmount)意味著狀態(tài)和 DOM 的徹底銷毀。如何在 React 中實現(xiàn)“切換頁面不丟失滾動位置、不重置表單”?本文將為你拆解三種主流方案。
一、 Keep-Alive 的本質(zhì)是什么?
在實現(xiàn) React 版緩存組件前,先明確 Vue keep-alive 的核心邏輯,才能精準復刻:
- 核心本質(zhì):緩存組件實例,保留組件內(nèi)部狀態(tài)(如輸入框內(nèi)容、滾動位置);
- 行為特征:組件切換時不銷毀 / 重建,僅通過「隱藏 / 顯示」控制渲染狀態(tài);
- React 目標:實現(xiàn)和 Vue 一致的效果 —— 組件切走不丟狀態(tài),切回來能恢復。
二、 React 實現(xiàn) keep-alive 的 3 種方案
方案 1:CSS 隱藏 + 不卸載組件(最簡單)
核心思路:
通過 display: none 隱藏不活躍的組件,保留組件的 DOM 節(jié)點和內(nèi)部狀態(tài),僅切換 display 屬性控制顯示 / 隱藏,不觸發(fā)組件的卸載 / 重新掛載生命周期。
適用場景
- 少量組件切換(2-3 個,如 tab 標簽頁);
- 簡單業(yè)務場景(如表單頁、列表頁切換)。
優(yōu)缺點
? 優(yōu)點:實現(xiàn)簡單,無額外依賴,狀態(tài)保留完整;
? 缺點:所有組件都會掛載在 DOM 樹中,組件數(shù)量多(如 5 個以上)會增加 DOM 節(jié)點數(shù)量,可能影響頁面渲染性能。
import { useState } from 'react';
// 模擬 Tab 切換場景
const KeepAliveByCSS = () => {
// 控制當前激活的標簽
const [activeKey, setActiveKey] = useState('tab1');
return (
<div>
<div className="tab-header">
<button onClick={() => setActiveKey('tab1')}>標簽1</button>
<button onClick={() => setActiveKey('tab2')}>標簽2</button>
</div>
<div className="tab-content">
{/* 始終掛載,僅通過 CSS 隱藏 */}
<div style={{ display: activeKey === 'tab1' ? 'block' : 'none' }}>
<Tab1 />
</div>
<div style={{ display: activeKey === 'tab2' ? 'block' : 'none' }}>
<Tab2 />
</div>
</div>
</div>
);
};
// 帶狀態(tài)的子組件
const Tab1 = () => {
// 切換標簽后,輸入框內(nèi)容不會丟失
const [inputVal, setInputVal] = useState('');
return <input value={inputVal} onChange={(e) => setInputVal(e.target.value)} placeholder="標簽1輸入框" />;
};
const Tab2 = () => {
const [count, setCount] = useState(0);
return (
<div>
<p>計數(shù):{count}</p>
<button onClick={() => setCount(count + 1)}>增加</button>
</div>
);
};方案 2:使用react-activation第三方庫(推薦)
這是目前社區(qū)內(nèi)最成熟的方案,它通過將組件渲染到“外部容器”再動態(tài)掛載回來的方式,模擬了 Vue 的行為。
核心功能
- 提供
<KeepAlive>容器組件,包裹需要緩存的組件即可生效; - 內(nèi)置
useActivate/useDeactivate鉤子函數(shù),分別在組件「激活」和「失活」時觸發(fā); - 支持緩存控制(如指定緩存 Key、條件緩存);
- 能保留 DOM 狀態(tài)(如滾動條位置、輸入框焦點)。
使用示例
import { KeepAlive, useActivate, useDeactivate } from 'react-activation';
import { useState } from 'react';
const KeepAliveByLib = () => {
const [show, setShow] = useState(true);
return (
<div>
<button onClick={() => setShow(!show)}>
{show ? '隱藏組件' : '顯示組件'}
</button>
{/* 用 KeepAlive 包裹需要緩存的組件 */}
{show && (
<KeepAlive id="cached-component">
<CachedComponent />
</KeepAlive>
)}
</div>
);
};
// 被緩存的組件
const CachedComponent = () => {
const [inputVal, setInputVal] = useState('');
const [scrollTop, setScrollTop] = useState(0);
// 組件激活時觸發(fā)(顯示時)
useActivate(() => {
console.log('組件被激活');
});
// 組件失活時觸發(fā)(隱藏時)
useDeactivate(() => {
console.log('組件被失活');
});
// 模擬滾動條狀態(tài)保留
const handleScroll = (e) => {
setScrollTop(e.target.scrollTop);
};
return (
<div>
<input
value={inputVal}
onChange={(e) => setInputVal(e.target.value)}
placeholder="緩存的輸入框"
/>
<div
style={{ height: '200px', overflow: 'auto', marginTop: '10px' }}
onScroll={handleScroll}
>
{Array.from({ length: 50 }).map((_, index) => (
<p key={index}>滾動測試行 {index + 1}</p>
))}
</div>
<p>當前滾動位置:{scrollTop}</p>
</div>
);
};方案 3:全局狀態(tài)管理 + 狀態(tài)回顯(Redux)
如果不想引入第三方庫,也可以通過全局狀態(tài)緩存實現(xiàn)核心效果,本質(zhì)是組件卸載前存狀態(tài),重新掛載時取狀態(tài)。
核心思路
在組件 useEffect 的清理函數(shù)中,將關(guān)鍵數(shù)據(jù)(輸入框、計數(shù)、滾動位置等)保存到全局 Store;重新掛載時再讀取初始化。
優(yōu)點:符合 React 數(shù)據(jù)流規(guī)范,內(nèi)存占用可控。
缺點:
- 無法恢復 DOM 狀態(tài):如頁面的滾動位置、輸入框的焦點、已播放的視頻進度,需單獨編寫邏輯處理。
- 開發(fā)成本高:每個需要緩存的組件都要手動編寫保存/恢復邏輯。
補救措施:若要恢復滾動位置,需手動在卸載前記錄
scrollTop,并在渲染后通過window.scrollTo還原。
三、緩存 React Router 路由組件
實際開發(fā)中,最常見的場景是切換路由不丟失頁面狀態(tài)(如列表頁滾動位置、表單輸入內(nèi)容),可結(jié)合 React Router + react-activation 實現(xiàn)。
核心代碼如下:
import { BrowserRouter, Routes, Route, useLocation } from 'react-router-dom';
import { KeepAlive } from 'react-activation';
import Profile from './pages/Profile';
import Home from './pages/Home';
import Settings from './pages/Settings';
// 路由容器組件(獲取當前路由路徑)
const RouterContainer = () => {
const location = useLocation();
const currentPath = location.pathname;
return (
<Routes>
{/* 普通路由(不緩存) */}
<Route path="/" element={<Home />} />
<Route path="/settings" element={<Settings />} />
{/* 緩存路由組件:when 控制是否緩存,id 為緩存標識 */}
<Route
path="/profile"
element={
<KeepAlive id="profile" when={currentPath === "/profile"}>
<Profile />
</KeepAlive>
}
/>
</Routes>
);
};
// 根組件
const App = () => {
return (
<BrowserRouter>
<RouterContainer />
</BrowserRouter>
);
};四、 方案選擇建議
| 方案 | 優(yōu)點 | 缺點 | 適用場景 |
|---|---|---|---|
| CSS 隱藏 | 實現(xiàn)簡單、無依賴 | DOM 節(jié)點冗余、性能一般 | 少量組件(2-3 個)、簡單 tab 切換 |
| react-activation | 功能完整、支持 DOM 狀態(tài)緩存 | 新增第三方依賴 | 中大型項目、需完整 keep-alive 效果 |
| 全局狀態(tài)緩存 | 無額外依賴、貼合狀態(tài)管理 | 僅恢復數(shù)據(jù)、需手動處理 DOM | 已用全局狀態(tài)庫、僅需數(shù)據(jù)緩存 |
五、總結(jié)
- React 無原生 keep-alive,但可通過CSS 隱藏、react-activation 庫、全局狀態(tài)緩存3 種方案模擬核心效果;
- 簡單場景用 CSS 隱藏,中大型項目優(yōu)先選 react-activation(兼顧易用性和完整性);
- 路由組件緩存可結(jié)合 React Router + react-activation 實現(xiàn),核心是通過 KeepAlive 包裹路由元素并指定緩存標識。
到此這篇關(guān)于React手把手帶你實現(xiàn)Keep-Alive效果的三種方法的文章就介紹到這了,更多相關(guān)React實現(xiàn)Keep-Alive內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
在React框架中實現(xiàn)一些AngularJS中ng指令的例子
這篇文章主要介紹了在JavaScript的React框架中實現(xiàn)一些AngularJS指令的例子,React使用Virtual DOM因而與普通的js框架有些不同,需要的朋友可以參考下2016-03-03
React Native使用百度Echarts顯示圖表的示例代碼
本篇文章主要介紹了React Native使用百度Echarts顯示圖表的示例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-11-11
React?Native實現(xiàn)Toast輕提示和loading效果
這篇文章主要介紹了React Native實現(xiàn)Toast輕提示和loading效果,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-09-09

