SuperAPI AI 工具集

jotai-x

前端与建站

查看项目

更新于 10-16 06:09

技能介绍

用途

Jotai X 是一个基于 Jotai 的状态管理方案,围绕 createAtomStore 创建 store,并生成一组配套的 Provider 与 hook。它主要用于创建和消费 Jotai X store、在组件或回调中访问状态,以及把状态持久化到 cookie 或 localStorage。其核心目标是:最小化订阅、最大化性能。

核心原则

只有当组件需要在值变化时重新渲染,才使用 hook(useValue 类)订阅;其它情况一律使用 store 方法(store.get、store.set)直接读写。

// ✅ 只有在组件需要因变化重新渲染时才用 hook 订阅
const count = useAppValue("count");

// ✅ 在回调/处理器中读取而不订阅
const handleClick = () => {
  const count = store.get("count");
  console.log(count);
};

// ✅ 在回调/处理器中写入
const handleIncrement = () => {
  store.set("count", (prev) => prev + 1);
};

决策指南

读取状态:

  • 需要组件在值变化时重新渲染 → useAppValue('key')
  • 只需要一次性读取当前值 → store.get('key')
  • 在回调/事件处理器中 → store.get('key')
  • 在 useEffect 中 → 通常用 store.get('key'),除非需要作为依赖

写入状态:所有情况 → store.set('key', value)

同时需要读与写:不要使用 useAppState 或 useAppSet,改用上述组合。

速查表

场景 使用 不要使用
组件需要响应式 useAppValue('key') store.get('key')
回调中一次读取 store.get('key') useAppValue('key')
事件处理器读取 store.get('key') useAppValue('key')
任何写入操作 store.set('key', val) useAppSet('key')
需要读+写 useAppValue + store.set useAppState

API 参考

创建 store

import { createAtomStore } from "jotai-x";

export const {
  useChatStore,
  useChatValue,
  ChatProvider,
} = createAtomStore(
  {
    count: 0,
    name: "Alice",
    items: [] as string[],
  },
  {
    name: "chat",
  }
);

store 实例 API

const store = useChatStore();

store.get("count");
store.getCount();

store.set("count", 5);
store.set("count", (c) => c + 1);
store.setCount(5);

const unsub = store.subscribe("count", (value) => {
  console.log(value);
});

Hook API(尽量少用)

const count = useChatValue("count");

const firstItem = useChatValue(
  "items",
  {
    selector: (items) => items[0],
  },
  []
);

const items = useChatValue(
  "items",
  {
    equalityFn: (a, b) => a.length === b.length,
  },
  []
);

常见错误

  • 在回调中使用 hook:会创建不必要的订阅,并可能读到过期闭包值;应改用 store.get。
  • 使用 useAppState:属于过度订阅;应使用 useChatValue 订阅,并用 store.set 写入。
  • 使用 useAppSet:不必要的 hook 调用;应直接用 store.set。
  • 过度订阅:组件订阅了不参与渲染的值,应在需要时用 store.get 获取。

性能影响

不良模式中,组件订阅了 4 个 atom 但只在渲染中使用 2 个,任一变化都会触发重渲染;良好模式只订阅渲染所需的值,其余在回调中通过 store.get 获取。

持久化

在 store 定义中直接使用 atomWithCookie 或 atomWithLocalStorage 即可把值持久化到 cookie 或 localStorage。

存储选择:

  • Cookie:需要服务端访问、SSR 水合、小数据。
  • LocalStorage:仅客户端、较大数据、无需 SSR。

atomWithCookie(对 SSR 友好):

import { atomWithCookie } from "@/lib/utils/atomWithCookie";

export const { useChatStore, useChatValue, ChatProvider } = createAtomStore(
  {
    isOpen: atomWithCookie("chat_isOpen", true),
  },
  { name: "chat" }
);

服务端水合:

import { cookies } from "next/headers";
import { getCookieParser } from "@/lib/utils/getCookieParser";

export async function Layout({ children }) {
  const cookieStore = await cookies();
  const parser = getCookieParser(cookieStore);
  const isOpen = parser.boolean("chat_isOpen") ?? true;

  return <ChatProvider initialValues={{ isOpen }}>{children}</ChatProvider>;
}

Cookie 命名约定:prefix_key(如 chat_isOpen、chat_mode)。

atomWithLocalStorage(仅客户端):

import { atomWithLocalStorage } from "@/lib/utils/atomWithLocalStorage";

export const { useAppStore, useAppValue, AppProvider } = createAtomStore(
  {
    theme: atomWithLocalStorage("app_theme", "light"),
  },
  { name: "app" }
);

无需服务端水合,因为 localStorage 仅存在于客户端。

持久化常见错误:不要通过 extend 选项来实现持久化;应直接赋值 atomWithCookie / atomWithLocalStorage;使用 cookie 时不要忘记服务端水合,否则首屏会忽略 cookie 值。