Files
cozsweet-frontend-nextjs/src/stores/sidebar/sidebar-context.tsx
T

73 lines
2.1 KiB
TypeScript

"use client";
/**
* SidebarContext:基于 XState v5 的 React Context Provider
*
* 业务事件通过 `useMachine(sidebarMachine).send()` 派发。
* XState 自动处理状态转换(无异步副作用)。
*
* 兼容性:保持原 `useSidebarState()` / `useSidebarDispatch()` API。
* 内部将 XState 状态机快照映射回原 `SidebarState` 形状。
*/
import {
type Dispatch,
type ReactNode,
createContext,
useContext,
useMemo,
} from "react";
import { useMachine } from "@xstate/react";
import { sidebarMachine } from "./sidebar-machine";
import type {
SidebarState as MachineContext,
SidebarEvent,
} from "./sidebar-machine";
/**
* 对外暴露的 State 形状(保持与原 SidebarState 兼容)
*/
interface SidebarState {
currentPage: MachineContext["currentPage"];
selectedBottomNavItem: MachineContext["selectedBottomNavItem"];
characterName: string;
characterProgress: number;
}
const SidebarStateCtx = createContext<SidebarState | null>(null);
const SidebarDispatchCtx = createContext<Dispatch<SidebarEvent> | null>(null);
export function SidebarProvider({ children }: { children: ReactNode }) {
const [state, send] = useMachine(sidebarMachine, {});
// 映射 XState 状态机快照 → 原 SidebarState 形状
const sidebarState = useMemo<SidebarState>(
() => ({
currentPage: state.context.currentPage,
selectedBottomNavItem: state.context.selectedBottomNavItem,
characterName: state.context.characterName,
characterProgress: state.context.characterProgress,
}),
[state],
);
return (
<SidebarStateCtx.Provider value={sidebarState}>
<SidebarDispatchCtx.Provider value={send}>{children}</SidebarDispatchCtx.Provider>
</SidebarStateCtx.Provider>
);
}
export function useSidebarState(): SidebarState {
const ctx = useContext(SidebarStateCtx);
if (!ctx)
throw new Error("useSidebarState must be used inside <SidebarProvider>");
return ctx;
}
export function useSidebarDispatch(): Dispatch<SidebarEvent> {
const ctx = useContext(SidebarDispatchCtx);
if (!ctx)
throw new Error("useSidebarDispatch must be used inside <SidebarProvider>");
return ctx;
}