字节笔记本

2026年2月22日

React Keep Alive - 组件状态保持方案

本文介绍 react-keep-alive,一个用于 React 应用的组件状态保持库。它能够帮助开发者在组件切换时保持状态,避免重复渲染,特别适用于列表页到详情页的场景。

项目简介

react-keep-alive 是一个开源的 React 组件缓存库,由 StructureBuilder 组织开发维护。该项目在 GitHub 上已获得超过 1000 stars,使用 TypeScript 编写,提供了类似 Vue keep-alive 的功能。

该库的核心价值在于解决 React 应用中组件卸载后状态丢失的问题。当你从列表页进入详情页再返回时,列表页的状态(滚动位置、筛选条件等)能够被完整保留。

核心特性

  • 框架无关:不基于 React Router,可在任何需要缓存的地方使用
  • 简单易用:使用 <KeepAlive> 组件轻松包装需要缓存的组件
  • 动画支持:不使用 display: none | block 控制,支持过渡动画
  • Hooks 支持:完全兼容最新的 React Hooks
  • 手动控制:可手动控制组件是否需要保持活力
  • 生命周期扩展:提供 componentDidActivatecomponentWillUnactivate 生命周期

技术栈

  • React:16.3+(使用 Hooks 需 16.8+)
  • TypeScript:完整类型支持
  • React Portals:使用 React.createPortal API 实现缓存机制

安装指南

前置要求

  • React >= 16.3
  • React DOM >= 16.3

安装步骤

bash
# 使用 npm 安装
npm install --save react-keep-alive

# 或使用 yarn
yarn add react-keep-alive

# 或使用 pnpm
pnpm add react-keep-alive

快速开始

基础用法

javascript
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider, KeepAlive } from 'react-keep-alive';
import Test from './views/Test';

ReactDOM.render(
  <Provider>
    <KeepAlive name="Test">
      <Test />
    </KeepAlive>
  </Provider>,
  document.getElementById('root'),
);

结合 React Router 使用

javascript
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';
import { Provider, KeepAlive } from 'react-keep-alive';

class One extends React.Component {
  render() {
    return <div>This is One.</div>;
  }
}

class App extends React.Component {
  render() {
    return (
      <div>
        <Switch>
          <Route path="/one">
            <KeepAlive name="One">
              <One />
            </KeepAlive>
          </Route>
        </Switch>
      </div>
    );
  }
}

ReactDOM.render(
  <Router>
    <Provider>
      <App />
    </Provider>
  </Router>,
  document.getElementById('root'),
);

使用示例

场景 1:使用 include 属性控制缓存

javascript
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';
import { Provider, KeepAlive } from 'react-keep-alive';

class One extends React.Component {
  render() {
    return <div>This is One.</div>;
  }
}

class App extends React.Component {
  render() {
    return (
      <div>
        <Switch>
          <Route path="/one">
            <KeepAlive name="One">
              <One />
            </KeepAlive>
          </Route>
        </Switch>
      </div>
    );
  }
}

ReactDOM.render(
  <Router>
    <Provider include="One">
      <App />
    </Provider>
  </Router>,
  document.getElementById('root'),
);

场景 2:使用 bindLifecycle 高阶组件

javascript
import React from 'react';
import { bindLifecycle } from 'react-keep-alive';

@bindLifecycle
class Test extends React.Component {
  componentDidActivate() {
    console.log('组件被激活');
  }

  componentWillUnactivate() {
    console.log('组件将被取消激活');
  }

  render() {
    return <div>This is Test.</div>;
  }
}

场景 3:使用 useKeepAliveEffect Hook

javascript
import React from 'react';
import { useKeepAliveEffect } from 'react-keep-alive';

function Test() {
  useKeepAliveEffect(() => {
    console.log('mounted');
    return () => {
      console.log('unmounted');
    };
  });

  return <div>This is Test.</div>;
}

API 参考

Provider

应用程序的根组件,用于存储缓存的组件。

Props

属性类型说明
includestring | string[] | RegExp只缓存匹配的组件
excludestring | string[] | RegExp不缓存匹配的组件
maxnumber最大缓存数量(v2.5.2+)

KeepAlive

用于包装需要缓存的组件。

Props

属性类型必填说明
namestring唯一标识符
disabledboolean是否禁用缓存
extraany额外数据(v2.0.1+)

bindLifecycle

高阶组件,为被包装组件添加正确的生命周期。

useKeepAliveEffect

Hook,在组件进入和离开时触发,替代 useEffect。

注意事项

  1. DOM 要求<KeepAlive> 包裹的组件内部最外层必须有一个真实的 DOM 标签
  2. React Router 版本:如果使用 React Router,需要确保是最新版本以兼容 new Context API
  3. 唯一 name:同一 <Provider> 下的所有 <KeepAlive>name 必须唯一
  4. 生命周期:如需使用生命周期,请将组件包装在 bindLifecycle

项目链接

分享: