xstate
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseXState v5 Developer Guide
XState v5开发者指南
This skill provides comprehensive guidelines, patterns, and best practices for working with the XState v5 ecosystem in this project, including:
- XState State Machines - Finite state machines and actors for complex application logic
- @xstate/store - Simple event-driven stores for lightweight state management
- XState + TanStack Query - Integration patterns for data fetching orchestration
本指南提供了在项目中使用XState v5生态系统的综合指引、模式和最佳实践,涵盖:
- XState状态机 - 用于处理复杂应用逻辑的有限状态机和actor
- @xstate/store - 用于轻量级状态管理的简单事件驱动存储
- XState + TanStack Query - 用于数据获取编排的集成模式
Quick Reference
快速参考
| Use Case | Tool | Reference |
|---|---|---|
| Complex state flows, guards, hierarchical states | XState Machines | |
| Simple event-driven state, atoms, undo/redo | @xstate/store | |
| Data fetching with state orchestration | XState + TanStack Query | |
| 使用场景 | 工具 | 参考文档 |
|---|---|---|
| 复杂状态流、守卫、层级状态 | XState Machines | |
| 简单事件驱动状态、原子状态、撤销/重做 | @xstate/store | |
| 带状态编排的数据获取 | XState + TanStack Query | |
Core Principles
核心原则
XState State Machines
XState状态机
- Explicit States: Model application logic as explicit finite states and events
- Actor Model: Embrace the actor model for complex orchestration
- Impossible States: Use statecharts to eliminate impossible states
- Declarative Thinking: Think declaratively about state transitions
- Visualization: Use Stately Editor for visual machine creation and debugging
- 显式状态:将应用逻辑建模为显式的有限状态和事件
- Actor模型:采用Actor模型实现复杂编排
- 消除不可能状态:使用状态图消除不可能存在的状态
- 声明式思维:以声明式的思路设计状态转换
- 可视化:使用Stately Editor可视化创建和调试状态机
@xstate/store
@xstate/store
- Event-Driven Updates: Use events for all state updates (never direct mutations)
- Keep Stores Simple: Focus on data management, not complex logic
- Optimized Subscriptions: Leverage selectors for efficient state access
- Reactive State: Use atoms for composable, reactive state
- Upgrade Path: Migrate to XState machines when complexity grows
- 事件驱动更新:所有状态更新都通过事件实现(禁止直接修改状态)
- 保持存储简单:聚焦数据管理,不要承载复杂逻辑
- 优化订阅:利用选择器实现高效的状态访问
- 响应式状态:使用原子状态实现可组合的响应式状态
- 升级路径:复杂度提升时可迁移到XState状态机
XState + TanStack Query Integration
XState + TanStack Query集成
- XState for Orchestration: Use XState machines for workflow orchestration
- TanStack Query for Data: Use TanStack Query for data fetching and caching
- Actors as Bridges: Wrap Query operations as XState actors
- Cache Updates in Mutations: Keep query cache updates in mutation callbacks
- XState负责编排:使用XState状态机实现工作流编排
- TanStack Query负责数据:使用TanStack Query实现数据获取和缓存
- Actor作为桥梁:将Query操作封装为XState Actor
- 变更中更新缓存:将查询缓存的更新逻辑放在变更回调中
XState State Machines
XState状态机
Creating a Machine with setup() API
使用setup() API创建状态机
Always use the API for type-safe machines:
setup()typescript
import { setup, createActor } from 'xstate';
export enum CounterEventType {
INCREMENT = 'increment',
DECREMENT = 'decrement',
}
const counterMachineSetup = setup({
types: {
context: {} as { count: number },
events: {} as
| { type: CounterEventType.INCREMENT }
| { type: CounterEventType.DECREMENT },
input: {} as { initialCount: number },
},
guards: {
isPositive: ({ context }) => context.count > 0,
},
});
// Define actions OUTSIDE setup using type-bound helpers
const incrementCount = counterMachineSetup.assign({
count: ({ context }) => context.count + 1,
});
export const counterMachine = counterMachineSetup.createMachine({
id: 'counter',
context: ({ input }) => ({ count: input.initialCount }),
initial: 'active',
states: {
active: {
on: {
[CounterEventType.INCREMENT]: {
actions: incrementCount,
},
},
},
},
});始终使用 API创建类型安全的状态机:
setup()typescript
import { setup, createActor } from 'xstate';
export enum CounterEventType {
INCREMENT = 'increment',
DECREMENT = 'decrement',
}
const counterMachineSetup = setup({
types: {
context: {} as { count: number },
events: {} as
| { type: CounterEventType.INCREMENT }
| { type: CounterEventType.DECREMENT },
input: {} as { initialCount: number },
},
guards: {
isPositive: ({ context }) => context.count > 0,
},
});
// Define actions OUTSIDE setup using type-bound helpers
const incrementCount = counterMachineSetup.assign({
count: ({ context }) => context.count + 1,
});
export const counterMachine = counterMachineSetup.createMachine({
id: 'counter',
context: ({ input }) => ({ count: input.initialCount }),
initial: 'active',
states: {
active: {
on: {
[CounterEventType.INCREMENT]: {
actions: incrementCount,
},
},
},
},
});React Integration
React集成
Use for component-scoped machines and for action overrides:
useMachine().provide()typescript
import { useMachine } from '@xstate/react';
import { useMemo } from 'react';
function Counter({ onExternalAction }) {
const machine = useMemo(
() =>
counterMachine.provide({
actions: {
logEvent: () => onExternalAction(),
},
}),
[onExternalAction]
);
const [state, send] = useMachine(machine);
return (
<button onClick={() => send({ type: CounterEventType.INCREMENT })}>
Count: {state.context.count}
</button>
);
}For detailed patterns: See
references/machine-patterns.md针对组件级状态机使用,通过覆盖动作:
useMachine().provide()typescript
import { useMachine } from '@xstate/react';
import { useMemo } from 'react';
function Counter({ onExternalAction }) {
const machine = useMemo(
() =>
counterMachine.provide({
actions: {
logEvent: () => onExternalAction(),
},
}),
[onExternalAction]
);
const [state, send] = useMachine(machine);
return (
<button onClick={() => send({ type: CounterEventType.INCREMENT })}>
Count: {state.context.count}
</button>
);
}详细模式请参考:
references/machine-patterns.md@xstate/store
@xstate/store
Creating a Store
创建存储
Define stores with clear initial context and event-based transitions:
typescript
import { createStore } from '@xstate/store';
const userStore = createStore({
context: {
user: null as { id: string; name: string } | null,
isLoading: false,
error: null as string | null,
},
on: {
setUser: (context, event: { user: { id: string; name: string } }) => ({
...context, // Always spread to preserve other properties
user: event.user,
error: null,
}),
setLoading: (context, event: { isLoading: boolean }) => ({
...context,
isLoading: event.isLoading,
}),
},
});
// Use the trigger API for type-safe event sending
userStore.trigger.setUser({ user: { id: '1', name: 'John' } });定义存储时需明确初始上下文和基于事件的转换:
typescript
import { createStore } from '@xstate/store';
const userStore = createStore({
context: {
user: null as { id: string; name: string } | null,
isLoading: false,
error: null as string | null,
},
on: {
setUser: (context, event: { user: { id: string; name: string } }) => ({
...context, // Always spread to preserve other properties
user: event.user,
error: null,
}),
setLoading: (context, event: { isLoading: boolean }) => ({
...context,
isLoading: event.isLoading,
}),
},
});
// Use the trigger API for type-safe event sending
userStore.trigger.setUser({ user: { id: '1', name: 'John' } });React Integration
React集成
typescript
import { useSelector, useStore } from '@xstate/store/react';
function Counter() {
const store = useStore({
context: { count: 0 },
on: {
increment: (context, event: { by: number }) => ({
...context,
count: context.count + event.by,
}),
},
});
const count = useSelector(store, (state) => state.context.count);
return <button onClick={() => store.trigger.increment({ by: 1 })}>{count}</button>;
}typescript
import { useSelector, useStore } from '@xstate/store/react';
function Counter() {
const store = useStore({
context: { count: 0 },
on: {
increment: (context, event: { by: number }) => ({
...context,
count: context.count + event.by,
}),
},
});
const count = useSelector(store, (state) => state.context.count);
return <button onClick={() => store.trigger.increment({ by: 1 })}>{count}</button>;
}Undo/Redo Pattern
撤销/重做模式
typescript
import { createStore } from '@xstate/store';
import { undoRedo } from '@xstate/store/undo';
const editorStore = createStore(
undoRedo({
context: { text: '' },
on: {
insertText: (context, event: { text: string }) => ({
...context,
text: context.text + event.text,
}),
},
})
);
editorStore.trigger.undo();
editorStore.trigger.redo();For detailed patterns: See
references/store-patterns.mdtypescript
import { createStore } from '@xstate/store';
import { undoRedo } from '@xstate/store/undo';
const editorStore = createStore(
undoRedo({
context: { text: '' },
on: {
insertText: (context, event: { text: string }) => ({
...context,
text: context.text + event.text,
}),
},
})
);
editorStore.trigger.undo();
editorStore.trigger.redo();详细模式请参考:
references/store-patterns.mdXState + TanStack Query Integration
XState + TanStack Query集成
Query Subscriptions with QueryObserver
使用QueryObserver实现查询订阅
Use with for reactive subscriptions:
fromCallbackQueryObservertypescript
import { fromCallback } from "xstate";
import { QueryObserver, type QueryClient } from "@tanstack/react-query";
const subscribeToQuery = fromCallback(({ input, sendBack }) => {
const { queryClient, entityId } = input as {
queryClient: QueryClient;
entityId: string;
};
const observer = new QueryObserver(queryClient, {
queryKey: ["data", entityId],
queryFn: async () => { /* fetch logic */ },
});
const unsubscribe = observer.subscribe((result) => {
if (result.data) {
sendBack({ type: "REMOTE_UPDATE", data: result.data });
}
});
// Emit current result immediately
const currentResult = observer.getCurrentResult();
if (currentResult.data) {
sendBack({ type: "REMOTE_UPDATE", data: currentResult.data });
}
return () => unsubscribe();
});结合和实现响应式订阅:
fromCallbackQueryObservertypescript
import { fromCallback } from "xstate";
import { QueryObserver, type QueryClient } from "@tanstack/react-query";
const subscribeToQuery = fromCallback(({ input, sendBack }) => {
const { queryClient, entityId } = input as {
queryClient: QueryClient;
entityId: string;
};
const observer = new QueryObserver(queryClient, {
queryKey: ["data", entityId],
queryFn: async () => { /* fetch logic */ },
});
const unsubscribe = observer.subscribe((result) => {
if (result.data) {
sendBack({ type: "REMOTE_UPDATE", data: result.data });
}
});
// Emit current result immediately
const currentResult = observer.getCurrentResult();
if (currentResult.data) {
sendBack({ type: "REMOTE_UPDATE", data: currentResult.data });
}
return () => unsubscribe();
});Mutations with useMutation
结合useMutation实现变更
Wrap hooks as actors and provide via :
useMutationfromPromise.provide()typescript
const machine = useMemo(
() =>
createDataMachine().provide({
actors: {
saveData: fromPromise(async ({ input }) => {
return await saveMutation.mutateAsync(input.data);
}),
},
}),
[saveMutation]
);For detailed patterns: See
references/query-patterns.md将钩子封装为 Actor,通过注入:
useMutationfromPromise.provide()typescript
const machine = useMemo(
() =>
createDataMachine().provide({
actors: {
saveData: fromPromise(async ({ input }) => {
return await saveMutation.mutateAsync(input.data);
}),
},
}),
[saveMutation]
);详细模式请参考:
references/query-patterns.mdEssential Patterns (All Tools)
核心模式(所有工具通用)
- Use for all machines - provides superior type inference
setup() - Use enums for event types - UPPER_SNAKE_CASE convention
- Define actions outside - use type-bound helpers like
setup()setup().assign() - Use for sequential actions - group related actions together
enqueueActions() - Use for React integration - override actions with external methods
.provide() - Initialize context from - use function form for dynamic initialization
input - Always spread in stores - preserve other properties
...context - Clean up subscriptions - return cleanup functions from callback actors
- 所有状态机都使用- 提供更优秀的类型推导能力
setup() - 事件类型使用枚举定义 - 遵循大写下划线命名规范
- 在外部定义动作 - 使用类型绑定的辅助方法如
setup()setup().assign() - 顺序动作使用- 将相关动作分组
enqueueActions() - React集成使用- 用外部方法覆盖动作
.provide() - 从初始化上下文 - 使用函数形式实现动态初始化
input - 存储中始终展开- 保留其他属性
...context - 清理订阅 - 从回调Actor中返回清理函数
When to Use Each Tool
各工具适用场景
Use XState State Machines When:
适合使用XState状态机的场景:
- Need finite states with specific transitions
- Need guards and conditional transition logic
- Need invoked actors for async orchestration
- Need hierarchical or parallel states
- Building complex multi-step workflows
- 需要具备明确转换规则的有限状态
- 需要守卫和条件转换逻辑
- 需要调用Actor实现异步编排
- 需要层级或并行状态
- 构建复杂的多步工作流
Use @xstate/store When:
适合使用@xstate/store的场景:
- Simple global or local state management
- Event-driven state updates without complex flows
- Need undo/redo functionality
- Want a lightweight alternative with upgrade path to XState
- 简单的全局或本地状态管理
- 无复杂流程的事件驱动状态更新
- 需要撤销/重做功能
- 需要轻量级方案,且未来可升级到XState
Use XState + TanStack Query When:
适合使用XState + TanStack Query的场景:
- Need to orchestrate data fetching with UI state
- Building real-time features with cache synchronization
- Managing complex async workflows with server state
- 需要结合UI状态编排数据获取逻辑
- 构建带缓存同步的实时功能
- 管理涉及服务端状态的复杂异步工作流
Common Pitfalls to Avoid
需要避免的常见陷阱
All XState Tools
所有XState工具通用
- Don't use generic parameters; use instead
setup() - Don't define actions inside ; define them outside using type-bound helpers
setup() - Don't use string literals for event types; use enums instead
- Don't mutate context directly; always use or return new objects
assign() - Don't make guards impure or with side effects
- Don't use deprecated v4 APIs (,
interpret(), etc.)cond - Don't forget to actors
.start()
- 不要使用泛型参数,改用
setup() - 不要在内部定义动作,通过类型绑定辅助方法在外部定义
setup() - 不要用字符串字面量作为事件类型,改用枚举
- 不要直接修改上下文,始终使用或返回新对象
assign() - 不要编写非纯或带副作用的守卫
- 不要使用已废弃的v4 API(、
interpret()等)cond - 不要忘记调用启动Actor
.start()
@xstate/store Specific
@xstate/store专属
- Never forget to spread in returns
...context - Never subscribe without cleanup
- Never use stores for complex state machines (migrate to XState)
- 永远不要忘记在返回值中展开
...context - 订阅必须配套清理逻辑
- 不要用存储实现复杂状态机(应迁移到XState)
TanStack Query Integration
TanStack Query集成相关
- Don't create QueryObserver outside callback actors
- Don't update query cache inside machine actions
- Don't pass mutation hooks directly to actors (wrap in )
fromPromise - Don't access QueryClient from closure; pass through context
- 不要在回调Actor外部创建QueryObserver
- 不要在状态机动作中更新查询缓存
- 不要直接将变更钩子传递给Actor(需用封装)
fromPromise - 不要从闭包中访问QueryClient,应通过上下文传递
Validation Checklist
验证检查清单
Before finishing any task involving XState ecosystem:
完成任何涉及XState生态的任务前,请检查:
For State Machines
状态机检查项
- Machine uses API for type safety
setup() - Event types are defined using enums
- Actions are defined outside using type-bound helpers
setup() - Context is initialized from using function form
input - Guards are pure functions without side effects
- React components use or
useMachine()useActorRef()
- 状态机使用API保证类型安全
setup() - 事件类型使用枚举定义
- 动作在外部通过类型绑定辅助方法定义
setup() - 上下文通过函数形式从初始化
input - 守卫是无副作用的纯函数
- React组件使用或
useMachine()useActorRef()
For @xstate/store
@xstate/store检查项
- Always spread in transition return values
...context - Use API for type-safe event sending
trigger - Create selectors for optimized subscriptions
- Clean up subscriptions in React components
- 转换返回值中始终展开
...context - 使用API实现类型安全的事件发送
trigger - 定义选择器优化订阅
- React组件中做好订阅清理
For TanStack Query Integration
TanStack Query集成检查项
- QueryObserver subscriptions are wrapped in
fromCallback - Mutations are wrapped in and provided via
fromPromise.provide() - Query cache updates happen in mutation callbacks, not machine actions
- Cleanup functions are returned from callback actors
- QueryClient is passed through machine input/context
- QueryObserver订阅封装在中
fromCallback - 变更通过封装并通过
fromPromise注入.provide() - 查询缓存更新在变更回调中执行,而非状态机动作中
- 回调Actor返回清理函数
- QueryClient通过状态机的input/context传递
Always
通用检查项
- Run type checks ()
pnpm run typecheck - Run tests ()
pnpm run test
- 运行类型检查()
pnpm run typecheck - 运行测试()
pnpm run test
Detailed Reference Documentation
详细参考文档
For comprehensive patterns, examples, and in-depth guidance, consult these reference files:
- - Complete XState machine patterns including hierarchical states, parallel states, actors, testing, and migration from v4
references/machine-patterns.md - - Full @xstate/store patterns including selectors, atoms, effects, undo/redo, and when to migrate to machines
references/store-patterns.md - - Complete TanStack Query integration patterns with QueryObserver, mutations, and full machine examples
references/query-patterns.md
如需了解完整模式、示例和深度指引,请参考以下文档:
- - 完整的XState状态机模式,涵盖层级状态、并行状态、Actor、测试以及v4迁移指南
references/machine-patterns.md - - 完整的@xstate/store模式,涵盖选择器、原子状态、副作用、撤销/重做以及何时迁移到状态机的指引
references/store-patterns.md - - 完整的TanStack Query集成模式,涵盖QueryObserver、变更以及完整的状态机示例
references/query-patterns.md