React 状态管理的“碎片化”

前言

三年前,我们还在 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 行代码搞定"拉取-缓存-重试"

tsx 复制代码
// 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 渲染逻辑

tsx 复制代码
// 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 -->|序列化| BStorage Worker B -->|BroadcastChannel| C(其他标签页) B -->|IDB| D(磁盘) C -->|重新读取| ECSS 变量 D -->|下次加载| FHydrate

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

tsx 复制代码
// 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 结构:

ts 复制代码
// legacy:userSlice
interface UserSlice {
  id: string;
  name: string;
  vip: boolean;
}

迁移 3 步曲

  1. 声明兼容类型
ts 复制代码
// migrate.ts
export const userCapsule = storage<UserSlice>('user', {
  id: '',
  name: '',
  vip: false,
  version: 1, // React 会根据 version 自动执行 migrate 函数
});
  1. 在根组件做一次"搬家中转"
tsx 复制代码
// 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. 业务组件直接订阅胶囊
tsx 复制代码
// 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组件\
useSelector"
SetCapsule"setUserCapsule" StorageWorker"Storage Worker" IndexedDB(IndexedDB) Broadcast"BroadcastChannel" OtherTab"其他标签页" UserBadge"UserBadge组件\
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% 的脑力放在产品逻辑而非"管数据"上。

相关推荐
退休倒计时14 小时前
【每日一题】LeetCode 146. LRU 缓存 TypeScript
算法·leetcode·缓存·typescript
kyriewen1 天前
TypeScript 高级类型:我用 infer 写了一个类型安全的 EventBus,终于搞懂了泛型约束
前端·javascript·typescript
月光刺眼1 天前
Bun + TypeScript 后端入门:从类型约束到 LLM API 调用
后端·typescript
天蓝色的鱼鱼2 天前
Node.js 现在能直接跑 TypeScript 了,tsx 和 ts-node 还需要吗?
前端·typescript·node.js
Oo9202 天前
Bun:下一代 JavaScript/TypeScript 运行时,从入门到实践
typescript·bun
Asize2 天前
Bun + TypeScript 实战:从接口约束到 RESTful 路由设计
后端·typescript·代码规范
大家的林语冰2 天前
超越 TypeScript,Flow 强势回归,语法高仿 TS,功能更丰富,类型更安全!
前端·javascript·typescript
用户484526255823 天前
Bun 入门:Bun.serve 零依赖启动 HTTP 服务
typescript
meilindehuzi_a4 天前
构建基于 RESTful 架构的 TodoList 全栈应用:从前后端理论到 TypeScript/Bun 实战
架构·typescript·restful
云水一下4 天前
Vue.js从零到精通系列(七):高级特性实战——Teleport、异步组件、自定义指令与TypeScript深度结合
前端·vue.js·typescript