与 Stencil 一起使用

Stencil web components work very well with XState.

src/helpers/toggle-machine.ts

  1. import { createMachine } from "@xstate/fsm";
  2. export const toggleMachine = createMachine<
  3. undefined,
  4. { type: "toggle" },
  5. { value: "active" | "inactive"; context: undefined }
  6. >({
  7. id: "toggle",
  8. initial: "active",
  9. states: {
  10. inactive: { on: { toggle: "active" } },
  11. active: { on: { toggle: "inactive" } }
  12. }
  13. });

src/components/toggle/toggle.tsx

Add a state property to your component, decorated with @State so that it triggers a re-render when changed.

On componentWillLoad, interpret the toggleMachine and listen for state transitions.

After a transition has occured, the state property is set to the machine’s new state, triggering a re-render.

  1. import { Component, h, State } from "@stencil/core";
  2. import { interpret } from "@xstate/fsm";
  3. import { toggleMachine } from "../helpers/toggle-machine";
  4. @Component({
  5. tag: "my-toggle",
  6. styleUrl: "toggle.css",
  7. shadow: true
  8. })
  9. export class Toggle {
  10. private _service = interpret(toggleMachine);
  11. @State() state = toggleMachine.initialState;
  12. componentWillLoad() {
  13. this._service.subscribe(state => {
  14. this.state = state;
  15. });
  16. this._service.start();
  17. }
  18. disconnectedCallback() {
  19. this._service.stop();
  20. }
  21. render() {
  22. const { send } = this._service;
  23. return (
  24. <button onClick={() => send("toggle")}>
  25. {this.state.value === "inactive" ? "Off" : "On"}
  26. </button>
  27. );
  28. }
  29. }

Your html page:

  1. <html>
  2. <head>
  3. <script type="module" src="/build/my-toggle.esm.js"></script>
  4. <script nomodule src="/build/my-toggle.js"></script>
  5. </head>
  6. <body>
  7. <my-toggle></my-toggle>
  8. </body>
  9. </html>