refactor: migrate state imports from contexts to stores directory

This commit is contained in:
2026-06-09 18:47:04 +08:00
parent f79755f6ec
commit a5d8214650
29 changed files with 72 additions and 50 deletions
+78
View File
@@ -0,0 +1,78 @@
"use client";
/**
* UserContext:基于 XState v5 的 React Context Provider
*
* 业务事件通过 `useMachine(userMachine).send()` 派发。
* XState 自动处理异步副作用(invoke + fromPromise actors)。
*
* 兼容性:保持原 `useUserState()` / `useUserDispatch()` API。
* 内部将 XState 状态机快照映射回原 `UserState` 形状。
*/
import {
type Dispatch,
type ReactNode,
createContext,
useContext,
useMemo,
} from "react";
import { useMachine } from "@xstate/react";
import { userMachine } from "./user-machine";
import type { UserContext as MachineContext, UserEvent } from "./user-machine";
/**
* 对外暴露的 State 形状(保持与原 UserState 兼容)
*/
export interface UserState {
currentUser: MachineContext["currentUser"];
pronouns: string;
coinBalance: number;
isLoading: boolean;
avatarUrl: string | null;
}
const UserStateCtx = createContext<UserState | null>(null);
const UserDispatchCtx = createContext<Dispatch<UserEvent> | null>(null);
export interface UserProviderProps {
children: ReactNode;
}
export function UserProvider({ children }: UserProviderProps) {
const [state, send] = useMachine(userMachine);
// 映射 XState 状态机快照 → 原 UserState 形状
const userState = useMemo<UserState>(
() => ({
currentUser: state.context.currentUser,
pronouns: state.context.pronouns,
coinBalance: state.context.coinBalance,
isLoading:
state.matches("initializing") ||
state.matches("fetching") ||
state.matches("loggingOut") ||
state.context.isLoading,
avatarUrl: state.context.avatarUrl,
}),
[state],
);
return (
<UserStateCtx.Provider value={userState}>
<UserDispatchCtx.Provider value={send}>{children}</UserDispatchCtx.Provider>
</UserStateCtx.Provider>
);
}
export function useUserState(): UserState {
const ctx = useContext(UserStateCtx);
if (!ctx) throw new Error("useUserState must be used inside <UserProvider>");
return ctx;
}
export function useUserDispatch(): Dispatch<UserEvent> {
const ctx = useContext(UserDispatchCtx);
if (!ctx)
throw new Error("useUserDispatch must be used inside <UserProvider>");
return ctx;
}