Skip to content

Releases: statelyai/xstate

xstate@5.17.1

31 Jul 16:10
c62e1f8
Compare
Choose a tag to compare

Patch Changes

  • #5009 51d4c4fc5 Thanks @davidkpiano! - The internal types for StateMachine<...> have been improved so that all type params are required, to prevent errors when using the types. This fixes weird issues like #5008.

xstate@5.17.0

30 Jul 19:13
eac555e
Compare
Choose a tag to compare

Minor Changes

  • #4979 a0e9ebcef Thanks @davidkpiano! - State IDs are now strongly typed as keys of snapshot.getMeta() for state machine actor snapshots.

    const machine = setup({
      // ...
    }).createMachine({
      id: 'root',
      initial: 'parentState',
      states: {
        parentState: {
          meta: {},
          initial: 'childState',
          states: {
            childState: {
              meta: {}
            },
            stateWithId: {
              id: 'state with id',
              meta: {}
            }
          }
        }
      }
    });
    
    const actor = createActor(machine);
    
    const metaValues = actor.getSnapshot().getMeta();
    
    // Auto-completed keys:
    metaValues.root;
    metaValues['root.parentState'];
    metaValues['root.parentState.childState'];
    metaValues['state with id'];
    
    // @ts-expect-error
    metaValues['root.parentState.stateWithId'];
    
    // @ts-expect-error
    metaValues['unknown state'];

Patch Changes

  • #5002 9877d548b Thanks @davidkpiano! - Fix an issue where clearTimeout(undefined) was sometimes being called, which can cause errors for some clock implementations. See #5001 for details.

@xstate/store@2.0.0

30 Jul 19:13
eac555e
Compare
Choose a tag to compare

Major Changes

  • #5000 eeadb7121 Thanks @TkDodo! - - Replace use-sync-external-store/shim with useSyncExternalStore from React.
    • Do not memoize getSnapshot in useSyncExternalStore.
    • Implement getServerSnapshot in useSyncExternalStore.
    • Expect store to always be defined in useSelector
    • Update React types to v18 and testing library to v16.

xstate@5.16.0

26 Jul 14:08
ccaeb44
Compare
Choose a tag to compare

Minor Changes

  • #4996 5be796cd2 Thanks @ronvoluted! - The actor snapshot status type ('active' | 'done' | 'error' | 'stopped') is now exposed as SnapshotStatus

  • #4981 c4ae156b2 Thanks @davidkpiano! - Added sendParent to the enqueueActions feature. This allows users to enqueue actions that send events to the parent actor within the enqueueActions block.

    import { createMachine, enqueueActions } from 'xstate';
    
    const childMachine = createMachine({
      entry: enqueueActions(({ enqueue }) => {
        enqueue.sendParent({ type: 'CHILD_READY' });
      })
    });

xstate@5.15.0

13 Jul 02:08
9841fab
Compare
Choose a tag to compare

Minor Changes

  • #4976 452bce71e Thanks @with-heart! - Added exports for actor logic-specific ActorRef types: CallbackActorRef, ObservableActorRef, PromiseActorRef, and TransitionActorRef.

    Each type represents ActorRef narrowed to the corresponding type of logic (the type of self within the actor's logic):

    • CallbackActorRef: actor created by fromCallback

      import { fromCallback, createActor } from 'xstate';
      
      /** The events the actor receives. */
      type Event = { type: 'someEvent' };
      /** The actor's input. */
      type Input = { name: string };
      
      /** Actor logic that logs whenever it receives an event of type `someEvent`. */
      const logic = fromCallback<Event, Input>(({ self, input, receive }) => {
        self;
        // ^? CallbackActorRef<Event, Input>
      
        receive((event) => {
          if (event.type === 'someEvent') {
            console.log(`${input.name}: received "someEvent" event`);
            // logs 'myActor: received "someEvent" event'
          }
        });
      });
      
      const actor = createActor(logic, { input: { name: 'myActor' } });
      //    ^? CallbackActorRef<Event, Input>
    • ObservableActorRef: actor created by fromObservable and fromEventObservable

      import { fromObservable, createActor } from 'xstate';
      import { interval } from 'rxjs';
      
      /** The type of the value observed by the actor's logic. */
      type Context = number;
      /** The actor's input. */
      type Input = { period?: number };
      
      /**
       * Actor logic that observes a number incremented every `input.period`
       * milliseconds (default: 1_000).
       */
      const logic = fromObservable<Context, Input>(({ input, self }) => {
        self;
        // ^? ObservableActorRef<Event, Input>
      
        return interval(input.period ?? 1_000);
      });
      
      const actor = createActor(logic, { input: { period: 2_000 } });
      //    ^? ObservableActorRef<Event, Input>
    • PromiseActorRef: actor created by fromPromise

      import { fromPromise, createActor } from 'xstate';
      
      /** The actor's resolved output. */
      type Output = string;
      /** The actor's input. */
      type Input = { message: string };
      
      /** Actor logic that fetches the url of an image of a cat saying `input.message`. */
      const logic = fromPromise<Output, Input>(async ({ input, self }) => {
        self;
        // ^? PromiseActorRef<Output, Input>
      
        const data = await fetch(`https://cataas.com/cat/says/${input.message}`);
        const url = await data.json();
        return url;
      });
      
      const actor = createActor(logic, { input: { message: 'hello world' } });
      //    ^? PromiseActorRef<Output, Input>
    • TransitionActorRef: actor created by fromTransition

      import { fromTransition, createActor, type AnyActorSystem } from 'xstate';
      
      /** The actor's stored context. */
      type Context = {
        /** The current count. */
        count: number;
        /** The amount to increase `count` by. */
        step: number;
      };
      /** The events the actor receives. */
      type Event = { type: 'increment' };
      /** The actor's input. */
      type Input = { step?: number };
      
      /**
       * Actor logic that increments `count` by `step` when it receives an event of
       * type `increment`.
       */
      const logic = fromTransition<Context, Event, AnyActorSystem, Input>(
        (state, event, actorScope) => {
          actorScope.self;
          //         ^? TransitionActorRef<Context, Event>
      
          if (event.type === 'increment') {
            return {
              ...state,
              count: state.count + state.step
            };
          }
          return state;
        },
        ({ input, self }) => {
          self;
          // ^? TransitionActorRef<Context, Event>
      
          return {
            count: 0,
            step: input.step ?? 1
          };
        }
      );
      
      const actor = createActor(logic, { input: { step: 10 } });
      //    ^? TransitionActorRef<Context, Event>
  • #4949 8aa4c2b90 Thanks @davidkpiano! - The TypeGen-related types have been removed from XState, simplifying the internal types without affecting normal XState usage.

xstate@5.14.0

22 Jun 06:52
11c781f
Compare
Choose a tag to compare

Minor Changes

  • #4936 c58b36dc3 Thanks @davidkpiano! - Inspecting an actor system via actor.system.inspect(ev => …) now accepts a function or observer, and returns a subscription:

    const actor = createActor(someMachine);
    
    const sub = actor.system.inspect((inspectionEvent) => {
      console.log(inspectionEvent);
    });
    
    // Inspection events will be logged
    actor.start();
    actor.send({ type: 'anEvent' });
    
    // ...
    
    sub.unsubscribe();
    
    // Will no longer log inspection events
    actor.send({ type: 'someEvent' });
  • #4942 9caaa1f70 Thanks @boneskull! - DoneActorEvent and ErrorActorEvent now contain property actorId, which refers to the ID of the actor the event refers to.

  • #4935 2ac08b700 Thanks @davidkpiano! - All actor logic creators now support emitting events:

    Promise actors

    const logic = fromPromise(async ({ emit }) => {
      // ...
      emit({
        type: 'emitted',
        msg: 'hello'
      });
      // ...
    });

    Transition actors

    const logic = fromTransition((state, event, { emit }) => {
      // ...
      emit({
        type: 'emitted',
        msg: 'hello'
      });
      // ...
      return state;
    }, {});

    Observable actors

    const logic = fromObservable(({ emit }) => {
      // ...
    
      emit({
        type: 'emitted',
        msg: 'hello'
      });
    
      // ...
    });

    Callback actors

    const logic = fromCallback(({ emit }) => {
      // ...
      emit({
        type: 'emitted',
        msg: 'hello'
      });
      // ...
    });

Patch Changes

  • #4929 417f35a11 Thanks @boneskull! - Expose type UnknownActorRef for use when calling getSnapshot() on an unknown ActorRef.

@xstate/store@1.0.0

12 Jun 07:02
28d437c
Compare
Choose a tag to compare

Major Changes

xstate@5.13.2

11 Jun 12:13
2d77f14
Compare
Choose a tag to compare

Patch Changes

xstate@5.13.1

01 Jun 15:58
deddaf2
Compare
Choose a tag to compare

Patch Changes

  • #4905 dbeafeb25 Thanks @davidkpiano! - You can now use a wildcard to listen for any emitted event from an actor:

    actor.on('*', (emitted) => {
      console.log(emitted); // Any emitted event
    });

@xstate/store@0.0.5

30 May 17:15
0a9af79
Compare
Choose a tag to compare

Patch Changes