XState logotype
Actor-based state management & orchestration for complex app logic. → Documentation

XState 是 JavaScript 和 TypeScript 应用的状态管理和编排解决方案。它具有零依赖,并且对于前端和后端应用逻辑很有用。

¥XState is a state management and orchestration solution for JavaScript and TypeScript apps. It has zero dependencies, and is useful for frontend and backend application logic.

它使用事件驱动编程、状态机、状态图和参与者模型以可预测、稳健和可视化的方式处理复杂逻辑。XState 允许开发者将逻辑建模为参与者和状态机,从而提供了一种强大而灵活的方法来管理应用和工作流状态。

¥It uses event-driven programming, state machines, statecharts, and the actor model to handle complex logic in predictable, robust, and visual ways. XState provides a powerful and flexible way to manage application and workflow state by allowing developers to model logic as actors and state machines.

# ✨ 在 Stately Studio 中直观地创建状态机 → state.new (opens new window)

¥✨ Create state machines visually in Stately Studio → state.new (opens new window)


📖 阅读文档 (opens new window)

¥📖 Read the documentation (opens new window)

➡️ 使用 Stately Editor 创建状态机 (opens new window)

¥➡️ Create state machines with the Stately Editor (opens new window)

🖥 下载我们的 VS Code 扩展 (opens new window)

¥🖥 Download our VS Code extension (opens new window)

📑 灵感来自 SCXML 规范 (opens new window)

¥📑 Inspired by the SCXML specification (opens new window)

💬 在 Stately Discord 社区 (opens new window) 上聊天

¥💬 Chat on the Stately Discord Community (opens new window)

#

¥Packages

描述
🤖 xstate 核心有限状态机和状态图库+解释器
📉 @xstate/graph (opens new window) XState 的图形遍历实用程序
⚛️ @xstate/react (opens new window) 用于在 React 应用中使用 XState 的 React 钩子和实用程序
💚 @xstate/vue (opens new window) 在 Vue 应用中使用 XState 的 Vue 组合函数和实用程序
🎷 @xstate/svelte (opens new window) 用于在 Svelte 应用中使用 XState 的 Svelte 实用程序
🥏 @xstate/solid (opens new window) 用于在 Solid 应用中使用 XState 的 Solid hook 和实用程序
@xstate/test (opens new window) 用于测试任何软件的基于模型的测试实用程序(使用 XState)
🔍 @xstate/inspect (opens new window) XState 的检查实用程序

# 模板

¥Templates

首先在 CodeSandbox 上复刻以下模板之一:

¥Get started by forking one of these templates on CodeSandbox:

模板
XState 模板 (opens new window) TypeScript,无框架
XState + React 模板 (opens new window) TypeScript、反应

# 超级快速启动

¥Super quick start

npm install xstate
import { createMachine, createActor, assign } from 'xstate';

// State machine
const toggleMachine = createMachine({
  id: 'toggle',
  initial: 'inactive',
  context: {
    count: 0
  },
  states: {
    inactive: {
      on: {
        TOGGLE: { target: 'active' }
      }
    },
    active: {
      entry: assign({ count: ({ context }) => context.count + 1 }),
      on: {
        TOGGLE: { target: 'inactive' }
      }
    }
  }
});

// Actor (instance of the machine logic, like a store)
const toggleActor = createActor(toggleMachine);
toggleActor.subscribe((state) => console.log(state.value, state.context));
toggleActor.start();
// => logs 'inactive', { count: 0 }

toggleActor.send({ type: 'TOGGLE' });
// => logs 'active', { count: 1 }

toggleActor.send({ type: 'TOGGLE' });
// => logs 'inactive', { count: 1 }

# Stately 工作室 (opens new window)

¥Stately Studio (opens new window)

  • 在状态机上直观地创建、编辑和协作

    ¥Visually create, edit, and collaborate on state machines

  • 导出为多种格式,包括 XState v5

    ¥Export to many formats, including XState v5

  • 测试路径和文档自动生成

    ¥Test path & documentation autogeneration

  • 部署到 Stately Sky

    ¥Deploy to Stately Sky

  • 使用 Stately AI 生成和修改机器

    ¥Generate & modify machines with Stately AI

XState Viz

state.new (opens new window)

# 为什么?

¥Why?

状态图是一种用于对有状态、反应式系统进行建模的形式。这对于以声明方式描述应用的行为(从单个组件到整个应用逻辑)非常有用。

¥Statecharts are a formalism for modeling stateful, reactive systems. This is useful for declaratively describing the behavior of your application, from the individual components to the overall application logic.

阅读 📽 幻灯片 (opens new window) (🎥 video (opens new window)) 或查看这些资源,了解有限状态机和状态图在用户界面中的重要性:

¥Read 📽 the slides (opens new window) (🎥 video (opens new window)) or check out these resources for learning about the importance of finite state machines and statecharts in user interfaces:

# 有限状态机

¥Finite State Machines

代码状态图
import { createMachine, createActor } from 'xstate';

const lightMachine = createMachine({
  id: 'light',
  initial: 'green',
  states: {
    green: {
      on: {
        TIMER: 'yellow'
      }
    },
    yellow: {
      on: {
        TIMER: 'red'
      }
    },
    red: {
      on: {
        TIMER: 'green'
      }
    }
  }
});

const actor = createActor(lightMachine);

actor.subscribe((state) => {
  console.log(state.value);
});

actor.start();
// logs 'green'

actor.send({ type: 'TIMER' });
// logs 'yellow'
代码 状态图
Finite states
Open in Stately Studio

# 分层(嵌套)状态机

¥Hierarchical (Nested) State Machines

代码状态图
import { createMachine, createActor } from 'xstate';

const pedestrianStates = {
  initial: 'walk',
  states: {
    walk: {
      on: {
        PED_TIMER: 'wait'
      }
    },
    wait: {
      on: {
        PED_TIMER: 'stop'
      }
    },
    stop: {}
  }
};

const lightMachine = createMachine({
  id: 'light',
  initial: 'green',
  states: {
    green: {
      on: {
        TIMER: 'yellow'
      }
    },
    yellow: {
      on: {
        TIMER: 'red'
      }
    },
    red: {
      on: {
        TIMER: 'green'
      },
      ...pedestrianStates
    }
  }
});

const actor = createActor(lightMachine);

actor.subscribe((state) => {
  console.log(state.value);
});

actor.start();
// logs 'green'

actor.send({ type: 'TIMER' });
// logs 'yellow'

actor.send({ type: 'TIMER' });
// logs { red: 'walk' }

actor.send({ type: 'PED_TIMER' });
// logs { red: 'wait' }
Hierarchical states
Open in Stately Studio

# 并行状态机

¥Parallel State Machines

代码状态图
import { createMachine, createActor } from 'xstate';

const wordMachine = createMachine({
  id: 'word',
  type: 'parallel',
  states: {
    bold: {
      initial: 'off',
      states: {
        on: {
          on: { TOGGLE_BOLD: 'off' }
        },
        off: {
          on: { TOGGLE_BOLD: 'on' }
        }
      }
    },
    underline: {
      initial: 'off',
      states: {
        on: {
          on: { TOGGLE_UNDERLINE: 'off' }
        },
        off: {
          on: { TOGGLE_UNDERLINE: 'on' }
        }
      }
    },
    italics: {
      initial: 'off',
      states: {
        on: {
          on: { TOGGLE_ITALICS: 'off' }
        },
        off: {
          on: { TOGGLE_ITALICS: 'on' }
        }
      }
    },
    list: {
      initial: 'none',
      states: {
        none: {
          on: {
            BULLETS: 'bullets',
            NUMBERS: 'numbers'
          }
        },
        bullets: {
          on: {
            NONE: 'none',
            NUMBERS: 'numbers'
          }
        },
        numbers: {
          on: {
            BULLETS: 'bullets',
            NONE: 'none'
          }
        }
      }
    }
  }
});

const actor = createActor(wordMachine);

actor.subscribe((state) => {
  console.log(state.value);
});

actor.start();
// logs {
//   bold: 'off',
//   italics: 'off',
//   underline: 'off',
//   list: 'none'
// }

actor.send({ type: 'TOGGLE_BOLD' });
// logs {
//   bold: 'on',
//   italics: 'off',
//   underline: 'off',
//   list: 'none'
// }

actor.send({ type: 'TOGGLE_ITALICS' });
// logs {
//   bold: 'on',
//   italics: 'on',
//   underline: 'off',
//   list: 'none'
// }
Parallel states
Open in Stately Studio

# 历史状态

¥History States

代码状态图
import { createMachine, createActor } from 'xstate';

const paymentMachine = createMachine({
  id: 'payment',
  initial: 'method',
  states: {
    method: {
      initial: 'cash',
      states: {
        cash: {
          on: {
            SWITCH_CHECK: 'check'
          }
        },
        check: {
          on: {
            SWITCH_CASH: 'cash'
          }
        },
        hist: { type: 'history' }
      },
      on: { NEXT: 'review' }
    },
    review: {
      on: { PREVIOUS: 'method.hist' }
    }
  }
});

const actor = createActor(paymentMachine);

actor.subscribe((state) => {
  console.log(state.value);
});

actor.start();
// logs {
//   value: { method: 'cash' },
// }

actor.send({ type: 'SWITCH_CHECK' });
// logs {
//   value: { method: 'check' },
// }

actor.send({ type: 'NEXT' });
// logs {
//   value: 'review',
// }

actor.send({ type: 'PREVIOUS' });
// logs {
//   value: { method: 'check' },
// }
History state
Open in Stately Studio

# 赞助商

¥Sponsors

特别感谢支持该开源项目的赞助商:

¥Special thanks to the sponsors who support this open-source project:

Transloadit Logo

# 语义版本政策

¥SemVer Policy

我们了解公共合约的重要性,并且不打算在次要版本或补丁版本中发布对运行时 API 的任何重大更改。我们对 XState 库所做的任何更改都会考虑到这一点,并旨在尽量减少其对现有用户的影响。

¥We understand the importance of the public contract and do not intend to release any breaking changes to the runtime API in a minor or patch release. We consider this with any changes we make to the XState libraries and aim to minimize their effects on existing users.

# 重大变化

¥Breaking changes

XState 本身执行大部分用户逻辑。因此,几乎任何对其行为的更改都可能被视为重大更改。我们认识到这是一个潜在的问题,但认为将每一次变更都视为重大变更是不切实际的。我们尽最大努力深思熟虑地实现新功能,使我们的用户能够以更好、更安全的方式实现他们的逻辑。

¥XState executes much of the user logic itself. Therefore, almost any change to its behavior might be considered a breaking change. We recognize this as a potential problem but believe that treating every change as a breaking change is not practical. We do our best to implement new features thoughtfully to enable our users to implement their logic in a better, safer way.

如果现有 XState 机器使用特定配置,则任何更改都可能影响这些机器的行为方式。我们不会一时兴起地引入行为改变,而是旨在避免做出影响大多数现有机器的改变。但我们保留在次要版本中进行一些行为更改的权利。我们对情况的最佳判断总是会决定这种变化。在决定升级之前,请务必阅读我们的发行说明。

¥Any change could affect how existing XState machines behave if those machines are using particular configurations. We do not introduce behavior changes on a whim and aim to avoid making changes that affect most existing machines. But we reserve the right to make some behavior changes in minor releases. Our best judgment of the situation will always dictate such changes. Please always read our release notes before deciding to upgrade.

# TypeScript 更改

¥TypeScript changes

我们还保留类似的权利来调整声明的 TypeScript 定义或在次要版本中放弃对旧版本 TypeScript 的支持。TypeScript 语言本身发展迅速,并且经常在其次要版本中引入重大更改。我们的团队也在不断学习如何更有效地利用 TypeScript - 结果类型得到改善。

¥We also reserve a similar right to adjust declared TypeScript definitions or drop support for older versions of TypeScript in a minor release. The TypeScript language itself evolves quickly and often introduces breaking changes in its minor releases. Our team is also continuously learning how to leverage TypeScript more effectively - and the types improve as a result.

由于这些原因,当旧版本的 TypeScript 是其最新版本或当我们不知道如何以更好的方式声明我们的类型时,我们的团队受到所做出的决定的约束是不切实际的。我们不会经常引入声明变更 - 但与运行时更改相比,我们更有可能这样做。

¥For these reasons, it is impractical for our team to be bound by decisions taken when an older version of TypeScript was its latest version or when we didn’t know how to declare our types in a better way. We won’t introduce declaration changes often - but we are more likely to do so than with runtime changes.

#

¥Packages

XState 系列中的大多数包都声明对 XState 本身的对等依赖。在发布新版本的 XState 时,我们会谨慎地维护与已发布的软件包的兼容性,但依赖于 XState 的每个软件包版本都会调整声明的对等依赖范围以包含最新版本的 XState。例如,你应该始终能够在没有 @xstate/react 的情况下更新 xstate。但是当你更新 @xstate/react 时,我们强烈建议你也更新 xstate

¥Most of the packages in the XState family declare a peer dependency on XState itself. We’ll be cautious about maintaining compatibility with already-released packages when releasing a new version of XState, but each release of packages depending on XState will always adjust the declared peer dependency range to include the latest version of XState. For example, you should always be able to update xstate without @xstate/react. But when you update @xstate/react, we highly recommend updating xstate too.