前言

三年前,我们还在 Reddit 上吵得不可开交:

“Redux 太啰嗦!” “Zustand 太黑盒!” “Jotai 会内存泄漏!”

今天,React 19 直接把“外挂仓库”拆成了无数颗微状态胶囊(Micro-State Capsules)——随用随取,随丢随灭。

状态不再集中,而是散落在组件树的最小粒度,靠框架自动合并、同步、持久化。

变化

场景 2022 痛点 2025 体感 补充示例
数据请求 手写 useEffect + swr,缓存键泛滥 use(promise) 同步写法,缓存自动化 见 3.1
全局主题 Context.Provider 层层包裹,重渲染噩梦 use(style) 原子化 CSS 变量,0 渲染成本 见 3.2
路由状态 路由库各自维护 location,跨页同步靠 hack use(navigation) 把路由当状态,页面间共享像 useState 见 3.3
客户端持久化 zustand-persist 手写版本号、迁移逻辑 use(storage) 声明式注册,React 后台自动合并、压缩、迁移 见 3.4

实战

3.1 数据请求:3 行代码搞定“拉取-缓存-重试”

// UserCard.tsx
export default function UserCard({ id }: { id: string }) {
// ① 接口返回 Promise,React 自动去重、缓存、过期重验证
const user = use(fetchUser(id)); // ← 同步写法,却具备 swr 全部能力 return (
<article>
<h1>{user.name}</h1>
<img src={user.avatar} alt={user.name} />
</article>
);
}

流程图:React 19 如何管理 use(promise)

sequenceDiagram
组件->>React: use(promise)
React->>缓存: 命中?
alt 命中
缓存-->>组件: 返回缓存数据
else 未命中
React->>服务端: 发起请求
服务端-->>React: 数据
React-->>缓存: 写入缓存
React-->>组件: 返回数据
end

3.2 主题切换:0 行 JavaScript 渲染逻辑

// DarkModeToggle.tsx
export default function DarkModeToggle() {
const [theme, setTheme] = use(storage('theme', 'light')); // 样式原子实时注入,不触发 React 渲染
use(style`
:root {
--bg: ${theme === 'dark' ? '#1e1e1e' : '#ffffff'};
--fg: ${theme === 'dark' ? '#ffffff' : '#1e1e1e'};
}
`); return (
<button onClick={() => setTheme(t => t === 'dark' ? 'light' : 'dark')}>
{theme === 'dark' ? '️' : ''}
</button>
);
}

架构图:主题胶囊在浏览器各线程间的流向

graph TD
A[组件setTheme] -->|序列化| B[Storage Worker]
B -->|BroadcastChannel| C(其他标签页)
B -->|IDB| D(磁盘)
C -->|重新读取| E[CSS 变量]
D -->|下次加载| F[Hydrate]

3.3 路由即状态:语言切换不再刷新整页

// LangSwitcher.tsx
export default function LangSwitcher() {
// 把 /[lang]/blog 中的 lang 当成状态
const [lang, setLang] = use(navigation().param('lang')); return (
<select value={lang} onChange={e => setLang(e.target.value)}>
<option value="en">English</option>
<option value="zh">中文</option>
</select>
);
}

关键点

  • 改变 lang 等价于 router.push,但 Next.js 15 会只 RSC 渲染变更区域
  • 若同一页面有多语言段落,React 会流式返回 diff,首字节时间 < 50 ms

3.4 持久化迁移:把 Redux Store 搬进“胶囊”

假设你有一个旧 userSlice 结构:

// legacy:userSlice
interface UserSlice {
id: string;
name: string;
vip: boolean;
}

迁移 3 步曲

  1. 声明兼容类型
// migrate.ts
export const userCapsule = storage<UserSlice>('user', {
id: '',
name: '',
vip: false,
version: 1, // React 会根据 version 自动执行 migrate 函数
});
  1. 在根组件做一次“搬家中转”
// App.tsx
function Bootstrap() {
const dispatch = useDispatch();
const legacyUser = useSelector(state => state.user); // ② 把 Redux 数据写入胶囊,只需一次
const [, setUserCapsule] = use(userCapsule);
useEffect(() => setUserCapsule(legacyUser), [legacyUser]); return <NextUI />;
}
  1. 业务组件直接订阅胶囊
// UserBadge.tsx
export default function UserBadge() {
const user = use(userCapsule); // ← 不再经过 Redux
return <span>{user.vip ? '' : ''} {user.name}</span>;
}

迁移流程图

graph LR
%% 节点定义
ReduxStore["Redux Store"]
Bootstrap["Bootstrap组件<br/>useSelector"]
SetCapsule["setUserCapsule"]
StorageWorker["Storage Worker"]
IndexedDB[(IndexedDB)]
Broadcast["BroadcastChannel"]
OtherTab["其他标签页"]
UserBadge["UserBadge组件<br/>use(userCapsule)"]

%% 连线
ReduxStore -->|读取| Bootstrap
Bootstrap -->|写入| SetCapsule
SetCapsule --> StorageWorker
StorageWorker -->|持久化| IndexedDB
StorageWorker -->|同步| Broadcast
Broadcast -->|触发更新| OtherTab
OtherTab -->|读取| UserBadge

迁移

  1. 渐进式切片

    把 Redux Store 拆成页面级 slice → 封装 toCapsule() 转换函数 → 灰度 10 % 用户。
  2. 双调度共存

    旧组件 createLegacyRoot() 跑旧调度器,新组件 createRoot() 跑微状态调度器,通过 useSyncExternalStore 双向同步。
  3. 类型即契约

    一份 GlobalState.d.ts 映射旧字段 → TypeScript 自动提示“无人订阅”字段 → 安全删除。

结语

当缓存、持久化、路由、样式都被框架做成声明式原语

我们终于可以把 100% 的脑力放在产品逻辑而非“管数据”上。

React 状态管理的“碎片化”的更多相关文章

  1. 借鉴redux,实现一个react状态管理方案

    react状态管理方案有很多,其中最简单的最常用的是redux. redux实现 redux做状态管理,是利用reducer和action实现的state的更新. 如果想要用redux,需要几个步骤 ...

  2. React状态管理相关

    关于React状态管理的一些想法 我最开始使用React的时候,那个时候版本还比较低(16版本以前),所以状态管理都是靠React自身API去进行管理,但当时最大的问题就是跨组件通信以及状态同步和状态 ...

  3. 纯粹极简的react状态管理组件unstated

    简介 unstated是一个极简的状态管理组件 看它的简介:State so simple, it goes without saying 对比 对比redux: 更加灵活(相对的缺点是缺少规则,需要 ...

  4. react状态管理器之mobx

    react有几种状态管理器,今天先来整理一下mobx状态管理器,首先了解一下什么是mobx 1.mobx成员: observable action 可以干嘛: MobX 的理念是通过观察者模式对数据做 ...

  5. react状态管理器(分模块)之redux和redux + react-redux + reducer和redux + react-redux + reducer分模块 + 异步操作redux-thunk

    1.回顾 cnpm i redux react-redux redux-thunk -S store/index.js src/index.js src/views/home/index.jsx + ...

  6. React状态管理之redux

    其实和vue对应的vuex都是差不多的东西,这里稍微提一下(安装Redux略过): import { createStore, combineReducers, applyMiddleware } f ...

  7. 你再也不用使用 Redux、Mobx、Flux 等状态管理了

    Unstated Next readme 的中文翻译 前言 这个库的作者希望使用 React 内置 API ,直接实现状态管理的功能.看完这个库的说明后,没有想到代码可以这个玩.短短几行代码,仅仅使用 ...

  8. Mobx-React : 当前适合React的状态管理工具

    MobX 简单.可扩展的状态管理        MobX 是由 Mendix.Coinbase.Facebook 开源和众多个人赞助商所赞助的.    安装 安装: npm install mobx ...

  9. React的状态管理工具

    Mobx-React : 当前最适合React的状态管理工具   MobX 简单.可扩展的状态管理        MobX 是由 Mendix.Coinbase.Facebook 开源和众多个人赞助商 ...

  10. react框架的状态管理

    安装: cnpm install --save redux cnpm install --save react-redux   安装好后导入模块内容: impor {createStore} from ...

随机推荐

  1. Solon StateMachine 实现状态机使用示例详解

    什么是状态机 状态机是计算机科学中的核心建模工具,用于描述对象在其生命周期内状态变化的逻辑模型.它通过定义有限状态集合.状态转移规则和触发事件,精确控制系统的行为逻辑. Solon StateMach ...

  2. 【QML】qt打包qml程序

    Debug版本程序依赖的dll文件很大,主要因为是debug版本程序中包含了调试信息,可以用来调试.而真正要发布程序时要使用release版本,这样可以减少发布程序的体积同时增加软件的安全. 1.先使 ...

  3. Swagger常用注解详解

    一.注解概述 常用注解: @Api()用于类: 表示标识这个类是swagger的资源 ,@Api 注解用于标注一个Controller(Class) @ApiOperation()用于方法: 表示一个 ...

  4. PHP 性能优化深度指南:那些被忽视的高效策略

    PHP 性能优化深度指南:那些被忽视的高效策略 PHP 驱动着网络的大部分内容,但和其他编程语言一样,只有做好性能优化才能发挥真正实力.PHP 确实以学习简单.开发快速著称,但当应用面临高并发时,问题 ...

  5. CF351C Jeff and Brackets

    CF351C Jeff and Brackets 广义矩阵加速 DP 题意 构造一个长度为 \(n×m\) 的合法括号序列. 第 \(i\) 个位置上的左括号代价为 \(a_{i~\text{mod} ...

  6. 从文档混乱到测试闭环:API 工具如何打通研发协作的堵点

    在日常开发中,"接口文档滞后于代码" 是一个反复出现的问题.前端开发联调支付接口经常会因为文档差异卡壳,经常是"看文档不如直接看代码". 文档维护:一个&quo ...

  7. 鸿蒙应用开发从入门到实战(十七):ArkUI组件List&列表布局

    大家好,我是潘Sir,持续分享IT技术,帮你少走弯路.<鸿蒙应用开发从入门到项目实战>系列文章持续更新中,陆续更新AI+编程.企业级项目实战等原创内容.欢迎关注! ArkUI提供了丰富的系 ...

  8. P11363 [NOIP2024] 树的遍历

    P11363 [NOIP2024] 树的遍历 题意 给你一个 \(n\) 个点的树,定义边与边相邻当且仅当它们有一个公共端点.一条合法 dfs 路径从某条边出发,如果存在未访问的相邻的边,则必须选择其 ...

  9. 【附源码】JAVA学生考试系统源码+SpringBoot+VUE+前后端分离

    学弟,学妹好,我是爱学习的学姐,今天带来一款优秀的项目:学生考试系统 . 本文介绍了系统功能与部署安装步骤,如果您有任何问题,也请联系学姐,偶现在是经验丰富的程序员! 一. 系统演示 系统测试截图 系 ...

  10. ShardingJDBC整合MybatisPlus的动态数据源

    依赖 <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-b ...