xstate-react

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

xState React

xState React

Your Role

你的角色

You are an expert in xState v5 actor-based state management with React and TypeScript. You understand state machines, statecharts, the actor model, and React integration patterns for managing complex application logic.
你是精通xState v5基于actor的状态管理、并熟悉React和TypeScript的专家。你了解状态机、状态图、actor模型,以及用于管理复杂应用逻辑的React集成模式。

Overview

概述

xState is an actor-based state management and orchestration solution for JavaScript and TypeScript applications. It uses event-driven programming, state machines, statecharts, and the actor model to handle complex logic in predictable, robust, and visual ways.
When to use xState:
  • Complex UI flows (multi-step forms, wizards, checkout processes)
  • State with many transitions and edge cases
  • Logic that needs to be visualized and validated
  • Processes with async operations and error handling
  • State that can be in multiple "modes" (loading, error, success, idle)
When to use simpler state instead (useState, Zustand):
  • Simple UI toggles and counters
  • Form state confined to a single component
  • State without complex transition logic
  • CRUD operations with straightforward loading states
xState是一款面向JavaScript和TypeScript应用的、基于actor的状态管理与编排解决方案。它采用事件驱动编程、状态机、状态图和actor模型,以可预测、健壮且可视化的方式处理复杂逻辑。
何时使用xState:
  • 复杂UI流程(多步骤表单、向导、结账流程)
  • 包含大量转换和边缘情况的状态
  • 需要可视化和验证的逻辑
  • 包含异步操作和错误处理的流程
  • 可能处于多种“模式”的状态(加载中、错误、成功、空闲)
何时使用更简单的状态管理方案(useState、Zustand):
  • 简单UI切换和计数器
  • 局限于单个组件的表单状态
  • 无复杂转换逻辑的状态
  • 具有简单加载状态的CRUD操作

Quick Start

快速开始

Create a state machine and use it in a React component:
typescript
"use client";

import { createMachine } from "xstate";
import { useMachine } from "@xstate/react";

const toggleMachine = createMachine({
  id: "toggle",
  initial: "inactive",
  states: {
    inactive: {
      on: { TOGGLE: "active" }
    },
    active: {
      on: { TOGGLE: "inactive" }
    }
  }
});

function Toggle() {
  const [state, send] = useMachine(toggleMachine);

  return (
    <button onClick={() => send({ type: "TOGGLE" })}>
      {state.value === "inactive" ? "Off" : "On"}
    </button>
  );
}
创建状态机并在React组件中使用:
typescript
"use client";

import { createMachine } from "xstate";
import { useMachine } from "@xstate/react";

const toggleMachine = createMachine({
  id: "toggle",
  initial: "inactive",
  states: {
    inactive: {
      on: { TOGGLE: "active" }
    },
    active: {
      on: { TOGGLE: "inactive" }
    }
  }
});

function Toggle() {
  const [state, send] = useMachine(toggleMachine);

  return (
    <button onClick={() => send({ type: "TOGGLE" })}>
      {state.value === "inactive" ? "Off" : "On"}
    </button>
  );
}

React Hooks API

React Hooks API

useMachine

useMachine

Create and run a machine within a component's lifecycle:
typescript
import { useMachine } from "@xstate/react";
import { someMachine } from "./machines/someMachine";

function Component() {
  const [state, send, actorRef] = useMachine(someMachine, {
    input: { userId: "123" } // Optional input
  });

  return (
    <div>
      <p>Current state: {JSON.stringify(state.value)}</p>
      <p>Context: {JSON.stringify(state.context)}</p>
      <button onClick={() => send({ type: "SOME_EVENT" })}>Send</button>
    </div>
  );
}
在组件生命周期内创建并运行状态机:
typescript
import { useMachine } from "@xstate/react";
import { someMachine } from "./machines/someMachine";

function Component() {
  const [state, send, actorRef] = useMachine(someMachine, {
    input: { userId: "123" } // 可选输入
  });

  return (
    <div>
      <p>当前状态: {JSON.stringify(state.value)}</p>
      <p>上下文: {JSON.stringify(state.context)}</p>
      <button onClick={() => send({ type: "SOME_EVENT" })}>发送事件</button>
    </div>
  );
}

useActor

useActor

Subscribe to an existing actor (created outside the component):
typescript
import { createActor } from "xstate";
import { useActor } from "@xstate/react";
import { todoMachine } from "./machines/todoMachine";

// Create actor outside component (e.g., in a module or context)
const todoActor = createActor(todoMachine);
todoActor.start();

function TodoApp() {
  const [state, send] = useActor(todoActor);

  return (
    <ul>
      {state.context.todos.map((todo) => (
        <li key={todo.id}>{todo.text}</li>
      ))}
    </ul>
  );
}
订阅已有的actor(在组件外部创建):
typescript
import { createActor } from "xstate";
import { useActor } from "@xstate/react";
import { todoMachine } from "./machines/todoMachine";

// 在组件外部创建actor(例如在模块或上下文环境中)
const todoActor = createActor(todoMachine);
todoActor.start();

function TodoApp() {
  const [state, send] = useActor(todoActor);

  return (
    <ul>
      {state.context.todos.map((todo) => (
        <li key={todo.id}>{todo.text}</li>
      ))}
    </ul>
  );
}

useSelector

useSelector

Optimize re-renders by selecting specific state:
typescript
import { useSelector } from "@xstate/react";

function TodoCount({ actorRef }) {
  // Only re-renders when todos.length changes
  const count = useSelector(actorRef, (state) => state.context.todos.length);

  return <span>{count} todos</span>;
}

function IsLoading({ actorRef }) {
  // Only re-renders when loading state changes
  const isLoading = useSelector(actorRef, (state) => state.matches("loading"));

  return isLoading ? <Spinner /> : null;
}
通过选择特定状态来优化重渲染:
typescript
import { useSelector } from "@xstate/react";

function TodoCount({ actorRef }) {
  // 仅当todos.length变化时才重渲染
  const count = useSelector(actorRef, (state) => state.context.todos.length);

  return <span>{count} 个待办事项</span>;
}

function IsLoading({ actorRef }) {
  // 仅当加载状态变化时才重渲染
  const isLoading = useSelector(actorRef, (state) => state.matches("loading"));

  return isLoading ? <Spinner /> : null;
}

TypeScript Patterns

TypeScript模式

Typing Machines with
types

使用
types
为状态机添加类型

Define context and events using the
types
property:
typescript
import { createMachine, assign } from "xstate";

type FormContext = {
  name: string;
  email: string;
  errors: string[];
};

type FormEvent =
  | { type: "UPDATE_NAME"; value: string }
  | { type: "UPDATE_EMAIL"; value: string }
  | { type: "SUBMIT" }
  | { type: "RESET" };

const formMachine = createMachine({
  types: {} as {
    context: FormContext;
    events: FormEvent;
  },
  id: "form",
  initial: "editing",
  context: {
    name: "",
    email: "",
    errors: []
  },
  states: {
    editing: {
      on: {
        UPDATE_NAME: {
          actions: assign({
            name: ({ event }) => event.value
          })
        },
        UPDATE_EMAIL: {
          actions: assign({
            email: ({ event }) => event.value
          })
        },
        SUBMIT: "submitting"
      }
    },
    submitting: {
      // ...
    }
  }
});
通过
types
属性定义上下文和事件:
typescript
import { createMachine, assign } from "xstate";

type FormContext = {
  name: string;
  email: string;
  errors: string[];
};

type FormEvent =
  | { type: "UPDATE_NAME"; value: string }
  | { type: "UPDATE_EMAIL"; value: string }
  | { type: "SUBMIT" }
  | { type: "RESET" };

const formMachine = createMachine({
  types: {} as {
    context: FormContext;
    events: FormEvent;
  },
  id: "form",
  initial: "editing",
  context: {
    name: "",
    email: "",
    errors: []
  },
  states: {
    editing: {
      on: {
        UPDATE_NAME: {
          actions: assign({
            name: ({ event }) => event.value
          })
        },
        UPDATE_EMAIL: {
          actions: assign({
            email: ({ event }) => event.value
          })
        },
        SUBMIT: "submitting"
      }
    },
    submitting: {
      // ...
    }
  }
});

Using
setup()
for Reusable Definitions

使用
setup()
定义可复用内容

Define actions, guards, actors, and delays in a type-safe way:
typescript
import { setup, assign } from "xstate";

type AuthContext = {
  userId: string | null;
  retries: number;
};

type AuthEvent =
  | { type: "LOGIN"; username: string; password: string }
  | { type: "LOGOUT" }
  | { type: "SUCCESS"; userId: string }
  | { type: "FAILURE" };

const authMachine = setup({
  types: {} as {
    context: AuthContext;
    events: AuthEvent;
  },
  actions: {
    setUser: assign({
      userId: ({ event }) => (event as { userId: string }).userId
    }),
    clearUser: assign({
      userId: null,
      retries: 0
    }),
    incrementRetries: assign({
      retries: ({ context }) => context.retries + 1
    })
  },
  guards: {
    hasReachedMaxRetries: ({ context }) => context.retries >= 3,
    isAuthenticated: ({ context }) => context.userId !== null
  }
}).createMachine({
  id: "auth",
  initial: "loggedOut",
  context: { userId: null, retries: 0 },
  states: {
    loggedOut: {
      on: {
        LOGIN: "authenticating"
      }
    },
    authenticating: {
      on: {
        SUCCESS: {
          target: "loggedIn",
          actions: "setUser"
        },
        FAILURE: [
          {
            guard: "hasReachedMaxRetries",
            target: "loggedOut",
            actions: "clearUser"
          },
          {
            actions: "incrementRetries"
          }
        ]
      }
    },
    loggedIn: {
      on: {
        LOGOUT: {
          target: "loggedOut",
          actions: "clearUser"
        }
      }
    }
  }
});
以类型安全的方式定义动作、守卫、actor和延迟:
typescript
import { setup, assign } from "xstate";

type AuthContext = {
  userId: string | null;
  retries: number;
};

type AuthEvent =
  | { type: "LOGIN"; username: string; password: string }
  | { type: "LOGOUT" }
  | { type: "SUCCESS"; userId: string }
  | { type: "FAILURE" };

const authMachine = setup({
  types: {} as {
    context: AuthContext;
    events: AuthEvent;
  },
  actions: {
    setUser: assign({
      userId: ({ event }) => (event as { userId: string }).userId
    }),
    clearUser: assign({
      userId: null,
      retries: 0
    }),
    incrementRetries: assign({
      retries: ({ context }) => context.retries + 1
    })
  },
  guards: {
    hasReachedMaxRetries: ({ context }) => context.retries >= 3,
    isAuthenticated: ({ context }) => context.userId !== null
  }
}).createMachine({
  id: "auth",
  initial: "loggedOut",
  context: { userId: null, retries: 0 },
  states: {
    loggedOut: {
      on: {
        LOGIN: "authenticating"
      }
    },
    authenticating: {
      on: {
        SUCCESS: {
          target: "loggedIn",
          actions: "setUser"
        },
        FAILURE: [
          {
            guard: "hasReachedMaxRetries",
            target: "loggedOut",
            actions: "clearUser"
          },
          {
            actions: "incrementRetries"
          }
        ]
      }
    },
    loggedIn: {
      on: {
        LOGOUT: {
          target: "loggedOut",
          actions: "clearUser"
        }
      }
    }
  }
});

Core Concepts

核心概念

States and Transitions

状态与转换

States represent the possible modes of your system. Transitions define how events move between states:
typescript
const machine = createMachine({
  initial: "idle",
  states: {
    idle: {
      on: { FETCH: "loading" }
    },
    loading: {
      on: {
        SUCCESS: "success",
        ERROR: "error"
      }
    },
    success: { type: "final" },
    error: {
      on: { RETRY: "loading" }
    }
  }
});
状态代表系统的可能模式。转换定义了事件如何在状态间切换:
typescript
const machine = createMachine({
  initial: "idle",
  states: {
    idle: {
      on: { FETCH: "loading" }
    },
    loading: {
      on: {
        SUCCESS: "success",
        ERROR: "error"
      }
    },
    success: { type: "final" },
    error: {
      on: { RETRY: "loading" }
    }
  }
});

Context

上下文

Context holds extended state data:
typescript
const machine = createMachine({
  context: {
    count: 0,
    user: null
  },
  // ...
});

// Access in component
const count = state.context.count;
上下文存储扩展状态数据:
typescript
const machine = createMachine({
  context: {
    count: 0,
    user: null
  },
  // ...
});

// 在组件中访问
const count = state.context.count;

Actions

动作

Actions are fire-and-forget side effects:
typescript
import { assign } from "xstate";

const machine = createMachine({
  // ...
  states: {
    active: {
      entry: assign({ count: ({ context }) => context.count + 1 }),
      exit: () => console.log("Leaving active state")
    }
  }
});
动作是一次性的副作用:
typescript
import { assign } from "xstate";

const machine = createMachine({
  // ...
  states: {
    active: {
      entry: assign({ count: ({ context }) => context.count + 1 }),
      exit: () => console.log("离开active状态")
    }
  }
});

Best Practices

最佳实践

DO

建议

  • Use
    setup()
    for type-safe action and guard definitions
  • Use
    useSelector
    for optimized state selection
  • Define explicit types for context and events
  • Use
    state.matches()
    for hierarchical state checking
  • Keep machines pure and side-effect-free (use actions for effects)
  • 使用
    setup()
    进行类型安全的动作和守卫定义
  • 使用
    useSelector
    优化状态选择
  • 为上下文和事件定义明确的类型
  • 使用
    state.matches()
    检查分层状态
  • 保持状态机纯净且无副作用(使用动作处理副作用)

DON'T

不建议

  • Don't store the entire snapshot object in React state
  • Don't mutate context directly (use
    assign
    )
  • Don't use xState for simple toggle/counter state
  • Don't forget to handle all possible states in your UI
  • 不要在React状态中存储整个快照对象
  • 不要直接修改上下文(使用
    assign
  • 不要将xState用于简单的切换/计数器状态
  • 不要忘记在UI中处理所有可能的状态

Client Component Requirement

客户端组件要求

xState hooks must be used in Client Components. Add the
"use client"
directive:
typescript
"use client";

import { useMachine } from "@xstate/react";
xState钩子必须在客户端组件中使用。添加
"use client"
指令:
typescript
"use client";

import { useMachine } from "@xstate/react";

Additional Documentation

额外文档

For comprehensive xState documentation including advanced patterns, use the Context7 MCP:
Use Context7 MCP with library ID "/statelyai/xstate" to fetch:
- Detailed invoke/spawn patterns
- Parallel and history states
- Actor communication
- Testing strategies
See
./references/patterns.md
for common patterns including async operations, guards, parallel states, and persistence.
如需包含高级模式的完整xState文档,请使用Context7 MCP:
使用库ID为"/statelyai/xstate"的Context7 MCP获取:
- 详细的invoke/spawn模式
- 并行状态和历史状态
- Actor通信
- 测试策略
查看
./references/patterns.md
获取包含异步操作、守卫、并行状态和持久化的常见模式。

Quick Reference

快速参考

TaskPattern
Create machine
createMachine({ id, initial, states, context })
Use in component
const [state, send] = useMachine(machine)
Check state
state.matches("loading")
or
state.value
Send event
send({ type: "EVENT_NAME", ...payload })
Read context
state.context.someValue
Update context
assign({ key: ({ context, event }) => newValue })
Conditional
guard: "guardName"
or
guard: ({ context }) => …
Async operation
invoke: { src: fromPromise(...), onDone, onError }
Optimized select
useSelector(actorRef, (state) => state.context.x)
任务实现模式
创建状态机
createMachine({ id, initial, states, context })
在组件中使用
const [state, send] = useMachine(machine)
检查状态
state.matches("loading")
state.value
发送事件
send({ type: "EVENT_NAME", ...payload })
读取上下文
state.context.someValue
更新上下文
assign({ key: ({ context, event }) => newValue })
条件判断
guard: "guardName"
guard: ({ context }) => …
异步操作
invoke: { src: fromPromise(...), onDone, onError }
优化状态选择
useSelector(actorRef, (state) => state.context.x)