AGENT SKILL

xstate

WHEN React state changes in response to an external answer — async submit, in-flight or loading flags, retries, cancellation, polling, optimistic updates, stale responses — or to an interaction with an interruptible middle, such as a drag or a gesture; or WHEN building, reviewing, testing, or visualising XState 5 actors and @xstate/react integrations; NOT for a value one event sets completely, such as a text draft, a focus flag, or a plain open and closed toggle; models typed lifecycles and renders legal Mermaid stateDiagram-v2 charts.

License 许可
MIT
所属仓库
mintuz/skills
最近更新
2026-11-13
Stars
★ 35
Forks
7

01 前言 Front Matter

name
xstate
description
WHEN React state changes in response to an external answer — async submit, in-flight or loading flags, retries, cancellation, polling, optimistic updates, stale responses — or to an interaction with an interruptible middle, such as a drag or a gesture; or WHEN building, reviewing, testing, or visualising XState 5 actors and @xstate/react integrations; NOT for a value one event sets completely, such as a text draft, a focus flag, or a plain open and closed toggle; models typed lifecycles and renders legal Mermaid stateDiagram-v2 charts.

02 资源文件 6

03 SKILL.md 正文

XState

Treat a statechart as an executable ownership model for time, concurrency, and resource lifetimes.

Recognise a hand-rolled statechart

Each of these is a lifecycle already modelled by hand:

  • a useState flag for work in flight: isSubmitting, isLoading, pending;
  • a .then, .catch, or await block that sets two or more pieces of state in sequence;
  • a re-entry guard such as if (submitting) return;
  • a line that clears an error or a stale result before a retry;
  • a useEffect that starts asynchronous work and needs an ignore flag in its cleanup;
  • two booleans that must never both be true, such as isLoading with error;
  • a setTimeout or setInterval for retry, debounce, or polling that something must clear;
  • a pointerdown, dragstart, or gesture handler that binds listeners to the document and must unbind them;
  • handling for a response that arrives after cancel, replacement, or unmount.

Any one of them leads to step 1, however small the request and whether or not the file imports xstate. When the code already exists, name each defect it has today and the wrong behaviour a user would see before proposing the machine that removes it (principle-capture-the-baseline).

For a visualisation-only request, inspect the current machine source and go to step 6 instead.

1. Establish the temporal boundary

Inventory the mounted journey, external authority, live resources, concurrent concerns, retry and cancellation policy, and every source of stale or duplicate work. Inspect existing actors and runtime integrations, and confirm the installed XState major version; the XState 4 and 5 APIs differ.

Use XState only where ordering, concurrency, retries, cancellation, stale results, or resource lifetimes make the behaviour temporal. Classify with two tests, by what they show, not by what the state renders:

  1. An external answer (a network response, a timer, another actor, the platform) makes state temporal whatever it looks like on screen. A disabled button or a spinner presents temporal state; it is not presentation state.
  2. Direct user input creates a lifecycle whenever the interaction has an interruptible middle: a drag holds pointer capture, cancels on Escape, and must release on unmount; a panel that animates shut has a closing phase.

State belongs to the UI framework only when both tests come back empty: one event sets the value completely, leaving no phase to interrupt and nothing to dispose.

Complete when: every temporal responsibility has one named owner, and every proposed actor owns at least one distinct lifecycle or resource.

2. Model the journey

Read modelling.md before creating or changing a machine. Apply it to the actor boundary, typed factory, event and command unions, lifecycle states, transition placement, hierarchy, parallel regions, and readiness joins.

Before creating the file, find which layer owns machines: architecture tests, import-boundary rules such as eslint-plugin-boundaries or dependency-cruiser, CLAUDE.md, architecture decision records, and the directory holding existing machines. A correct machine in a forbidden directory fails CI.

Complete when: the machine sits in the layer the repository's own rules assign to machines, mutually exclusive meanings are states, independent concerns are parallel only when they have independent lifecycles, and each transition sits at the narrowest state that owns it (principle-model-the-domain).

3. Own effects and convergence

Read lifecycles.md whenever the feature invokes asynchronous work, owns a live handle, retries, cancels, accepts optimistic state, or waits for external authority. Keep handles inside invoked actors and fence work by identity.

Complete when: state exit or parent stop disposes every resource, stale and duplicate results are harmless, retry timers cancel with their lifecycle, and authoritative convergence—not an optimistic acknowledgement—confirms completion.

4. Integrate React narrowly

Read react.md for any @xstate/react surface. Let the route or feature boundary own useActorRef, expose typed actor refs to descendants, and subscribe through focused selectors.

Run both step 1 tests over every useState you write or keep, and state the verdict in your reply so the user can overrule it. Where the tests are decisive, act and report the call in one line: "isSubmitting is set by the request, so it moved into the machine as submitting." Where the call is genuinely close (a real but small lifecycle, or a machine the repository's layer rules would push far from its component), ask the user before building: name the state, name the phase that makes it a lifecycle, and ask whether it belongs in the machine.

Complete when: every retained useState holds a value one event sets completely, no React state duplicates a fact an external answer owns, actor-derived status and permissions have one pure derivation, and each component subscribes only to values it renders or uses (principle-derive-from-one-owner).

5. Prove behaviour through actors

Read testing.md before writing or reviewing tests. Drive real actors with typed public events and fake ports; cover positive behaviour, negative space, stale identities, retries, cancellation, convergence, and teardown (principle-test-behavior-not-implementation).

Complete when: tests observe public actor behaviour, exactly-once cleanup is demonstrated, sendParent behaviour is exercised through a listening parent, and any model-based graph coverage is justified by chart complexity.

6. Render the statecharts

Read diagramming.md whenever the user asks for a diagram. After designing or changing any machine, render or update its diagrams even unasked.

Complete when: every designed or changed machine has a source-grounded diagram, composite and concurrent boundaries are legal, parser-sensitive labels are safe, and render validation is reported accurately.

Finish

Type-check the code against the project's installed XState and React adapters, run the actor and UI tests, and regenerate the diagrams from the final machine definitions.

Complete when: the implementation, tests, and diagrams account for every temporal branch and resource lifetime, without duplicating authoritative truth or presentation derivations.

04 同仓库更多 Skills

mintuz
mintuz/skills

web-design

WHEN refining UI layout, typography, color, or polish; NOT code implementation; provides concise principles for intentional, legible design.

设计师视觉设计
★ 35
mintuz
mintuz/skills

tailwind

USE WHEN writing, fixing or reviewing styling in a project that uses Tailwind CSS, even a one-class change or a request that does not name Tailwind: colours, focus rings, spacing, class names chosen by a prop, map or CVA variants, theme tokens and dark mode in the Tailwind stylesheet or tailwind.config, setup or upgrades (if unsure whether the project uses Tailwind, check package.json or the main stylesheet first); NOT WHEN writing plain CSS or Sass in a project without Tailwind; produces class names Tailwind can find, syntax for the installed major version, visible focus indicators, and no unrequested dependency or invented brand value.

视觉设计
★ 35
mintuz
mintuz/skills

refactoring

WHEN you need a plan to refactor, restructure, or clean up working code and the test result is known, either green or a recorded failing set; NOT for new feature delivery or any behavior change; reversible-baseline safety with prioritized improvements.

代码审查
★ 35
mintuz
mintuz/skills

react

USE WHEN changing the logic, data, props, state, Effects or rendered text of a React component, hook or page, even a one-line change; NOT WHEN the request is styling only (class names, Tailwind, CSS, dark mode, spacing, shadows) or tests only, or when it models submit, in-flight, loading, retry or failure states, even for a named React form (xstate covers that, including its React wiring); applies React 19 composition, state, Effect, structure, API and performance rules with only the project's installed libraries.

测试与质量前端开发
★ 35
mintuz
mintuz/skills

react-testing

USE WHEN writing, fixing or reviewing a React Testing Library test for a component, hook or context provider, even one small test, or when asked for an end-to-end journey inside a Vitest or React Testing Library suite; NOT WHEN changing the component itself (react), testing XState actors or @xstate/react (xstate), or writing a Playwright or Cypress test; covers renderHook, providers, async results, forms and false-pass anti-patterns, and declines end-to-end journeys with the testable slices.

测试与质量前端开发
★ 35
mintuz
mintuz/skills

frontend-testing

USE WHEN testing non-React UI (vanilla JavaScript or TypeScript DOM code, a web component, or a Vue, Svelte or Angular component) with DOM Testing Library in Vitest or Jest with jsdom: writing, fixing or reviewing a test, or a request to add an end-to-end journey or a layout check to that suite; NOT WHEN the code or project uses React or React Testing Library (use web:react-testing), for XState actors (web:xstate), or for Playwright, Cypress or screenshot-comparison work in a real browser; covers queries, accessible names, userEvent, async results, network stubs and assertions that pass for the wrong reason, and declines what jsdom cannot prove while offering the part that fits.

测试与质量前端开发
★ 35