"use client"; /** * UserContext:基于 XState actor context 和 selector 的 React Provider。 */ import type { Dispatch, ReactNode } from "react"; import { createActorContext, shallowEqual } from "@xstate/react"; import type { SnapshotFrom } from "xstate"; import { userMachine } from "./user-machine"; import type { UserState as MachineContext, UserEvent } from "./user-machine"; /** * 对外暴露的 State 形状(保持与原 UserState 兼容) */ interface UserState { currentUser: MachineContext["currentUser"]; isLoading: boolean; avatarUrl: string | null; isVip: boolean; creditBalance: number; entitlements: MachineContext["entitlements"]; } type UserSnapshot = SnapshotFrom; type UserSelector = (snapshot: UserSnapshot) => T; const UserActorContext = createActorContext(userMachine); export interface UserProviderProps { children: ReactNode; } export function UserProvider({ children }: UserProviderProps) { return {children}; } export function useUserState(): UserState { return useUserSelector(selectUserState, shallowEqual); } export function useUserDispatch(): Dispatch { return UserActorContext.useActorRef().send; } export function useUserSelector( selector: UserSelector, compare?: (previous: T, next: T) => boolean, ): T { return UserActorContext.useSelector(selector, compare); } function selectUserState(state: UserSnapshot): UserState { return { currentUser: state.context.currentUser, isLoading: state.matches("initializing") || state.matches("fetching") || state.matches("loggingOut") || state.context.isLoading, avatarUrl: state.context.avatarUrl, isVip: state.context.isVip, creditBalance: state.context.creditBalance, entitlements: state.context.entitlements, }; }