使用 Zustand 进行轻量级状态管理。
Store 结构
Thread 数据和用户 profile 数据通过 TanStack Query 从服务端获取,不使用 Zustand store。
Poisson Store
usePoissonStore(来自 store/poisson.ts)管理 Generator 相关状态,使用嵌套 map 模式 poissonMap[threadId] 存储每个 thread 的独立状态。
// store/poisson.ts
type EditMode = "chat" | "upscale" | "filter" | "adjust" | "crop" | "chooseFilter"
| "inpaint" | "expand" | "replaceBg" | "eraser" | "mask" | "video"
| "generateMusic" | "generateInstrumental" | "addVocals" | "generateImage";
type KiraModel = "lite" | "nova" | "crazy" | "ultra";
interface PoissonState {
// 模型选择(顶层,通过 persist 中间件持久化到 localStorage)
model: KiraModel;
// 嵌套 map,按 threadId 隔离状态
poissonMap: Record<string, {
currentImage: Image;
currentVersionId: string;
versions: Version[];
messages: UIMessage[];
tempMessages: UIMessage[];
executingTool: { toolName: string; args: object } | null;
chatStatus: ChatStatus;
inputState: InputState;
errorInfo: ToolError[] | null;
editMode: EditMode;
editModeData?: any;
isReceivingMessage: boolean;
isReceivingVersions: boolean;
currentSelectVideo?: Video;
currentSelectAudio?: Audio;
currentSelectMediaType: "image" | "video" | "audio";
}>;
// Actions(均需传入 threadId)
setCurrentImage: (threadId: string, image: Image) => void;
setEditMode: (threadId: string, mode: EditMode) => void;
}
export const usePoissonStore = create<PoissonState>(
persist(/* ... */, { name: 'poisson-store', partialize: (state) => ({ model: state.model }) })
);
Store 使用 Zustand 的 persist 中间件,通过 localStorage 持久化 model 字段。
Auth Store
useAuthStore(来自 store/auth.ts)仅管理认证状态。用户 profile 数据通过 TanStack Query 获取。
// store/auth.ts
interface AuthState {
isAuth: boolean;
login: () => void;
logout: () => void;
}
Feed State Store
useFeedStateStore(来自 store/feed.ts)管理 Feed 相关状态。
// store/feed.ts
interface FeedState {
deletedFeed: string[]; // 已删除的 feed ID 列表
localDeleteFeed: (feedId: string) => void; // 本地标记删除
localRecoverFeed: (feedId: string) => void; // 本地恢复
getDeletedFeed: (feedId: string) => boolean; // 判断是否已删除
}
使用方式
// 组件中使用
function ImagePanel({ threadId }: { threadId: string }) {
const currentImage = usePoissonStore(
(state) => state.poissonMap[threadId]?.currentImage
);
return <img src={currentImage?.url} />;
}
最佳实践
- 每个功能模块一个 Store
- 状态和 Actions 定义在同一个 Store 中
- 使用选择器避免不必要的重渲染