Skip to content

Releases: statelyai/xstate

@xstate/store@3.1.0

21 Feb 19:28
10e0d6d
Compare
Choose a tag to compare

Minor Changes

  • #5205 65784aef746b6249a9c3d71d9e4a7c9b454698c8 Thanks @davidkpiano! - Added createStoreConfig to create a store config from an object. This is an identity function that returns the config unchanged, but is useful for type inference.

    const storeConfig = createStoreConfig({
      context: { count: 0 },
      on: { inc: (ctx) => ({ ...ctx, count: ctx.count + 1 }) }
    });
    
    // Reusable store config:
    
    const store = createStore(storeConfig);
    
    // ...
    function Comp1() {
      const store = useStore(storeConfig);
    
      // ...
    }
    
    function Comp2() {
      const store = useStore(storeConfig);
    
      // ...
    }
  • #5205 65784aef746b6249a9c3d71d9e4a7c9b454698c8 Thanks @davidkpiano! - There is now a useStore() hook that allows you to create a local component store from a config object.

    import { useStore, useSelector } from '@xstate/store/react';
    
    function Counter() {
      const store = useStore({
        context: {
          name: 'David',
          count: 0
        },
        on: {
          inc: (ctx, { by }: { by: number }) => ({
            ...ctx,
            count: ctx.count + by
          })
        }
      });
      const count = useSelector(store, (state) => state.count);
    
      return (
        <div>
          <div>Count: {count}</div>
          <button onClick={() => store.trigger.inc({ by: 1 })}>
            Increment by 1
          </button>
          <button onClick={() => store.trigger.inc({ by: 5 })}>
            Increment by 5
          </button>
        </div>
      );
    }

Patch Changes

@xstate/store@3.0.1

14 Feb 12:26
08ade1a
Compare
Choose a tag to compare

Patch Changes

@xstate/store@3.0.0

10 Feb 14:34
a4f9ca3
Compare
Choose a tag to compare

Major Changes

  • #5175 38aa9f518ee2f9a5f481306a1dc68c0ad47d28d5 Thanks @davidkpiano! - The createStore function now only accepts a single configuration object argument. This is a breaking change that simplifies the API and aligns with the configuration pattern used throughout XState.

    // Before
    // createStore(
    //   {
    //     count: 0
    //   },
    //   {
    //     increment: (context) => ({ count: context.count + 1 })
    //   }
    // );
    
    // After
    createStore({
      context: {
        count: 0
      },
      on: {
        increment: (context) => ({ count: context.count + 1 })
      }
    });
  • #5175 38aa9f518ee2f9a5f481306a1dc68c0ad47d28d5 Thanks @davidkpiano! - You can now enqueue effects in state transitions.

    const store = createStore({
      context: {
        count: 0
      },
      on: {
        incrementDelayed: (context, event, enq) => {
          enq.effect(async () => {
            await new Promise((resolve) => setTimeout(resolve, 1000));
            store.send({ type: 'increment' });
          });
    
          return context;
        },
        increment: (context) => ({ count: context.count + 1 })
      }
    });
  • #5175 38aa9f518ee2f9a5f481306a1dc68c0ad47d28d5 Thanks @davidkpiano! - The fromStore(config) function now only supports a single config object argument.

    const storeLogic = fromStore({
      context: (input: { initialCount: number }) => ({
        count: input.initialCount
      }),
      on: {
        inc: (ctx, ev: { by: number }) => ({
          ...ctx,
          count: ctx.count + ev.by
        })
      }
    });
  • #5175 38aa9f518ee2f9a5f481306a1dc68c0ad47d28d5 Thanks @davidkpiano! - The createStoreWithProducer(…) function now only accepts two arguments: a producer and a config ({ context, on }) object.

    // Before
    // createStoreWithProducer(
    //   producer,
    //   {
    //     count: 0
    //   },
    //   {
    //     increment: (context) => {
    //       context.count++;
    //     }
    //   }
    // );
    
    // After
    createStoreWithProducer(producer, {
      context: {
        count: 0
      },
      on: {
        increment: (context) => {
          context.count++;
        }
      }
    });
  • #5175 38aa9f518ee2f9a5f481306a1dc68c0ad47d28d5 Thanks @davidkpiano! - Only complete assigner functions that replace the context fully are supported. This is a breaking change that simplifies the API and provides more type safety.

    const store = createStore({
      context: {
        items: [],
        count: 0
      },
      on: {
    -   increment: { count: (context) => context.count + 1 }
    -   increment: (context) => ({ count: context.count + 1 })
    +   increment: (context) => ({ ...context, count: context.count + 1 })
      }
    })
  • #5175 38aa9f518ee2f9a5f481306a1dc68c0ad47d28d5 Thanks @davidkpiano! - Emitted event types are now specified in functions on the emits property of the store definition:

    const store = createStore({
      // …
      emits: {
        increased: (payload: { upBy: number }) => {
          // You can execute a side-effect here
          // or leave it empty
        }
      },
      on: {
        inc: (ctx, ev: { by: number }, enq) => {
          enq.emit.increased({ upBy: ev.by });
    
          // …
        }
      }
    });

Minor Changes

  • #5175 38aa9f518ee2f9a5f481306a1dc68c0ad47d28d5 Thanks @davidkpiano! - Added store.trigger API for sending events with a fluent interface:

    const store = createStore({
      context: { count: 0 },
      on: {
        increment: (ctx, event: { by: number }) => ({
          count: ctx.count + event.by
        })
      }
    });
    
    // Instead of manually constructing event objects:
    store.send({ type: 'increment', by: 5 });
    
    // You can now use the fluent trigger API:
    store.trigger.increment({ by: 5 });

    The trigger API provides full type safety for event names and payloads, making it easier and safer to send events to the store.

xstate@5.19.2

12 Jan 18:45
3b43d84
Compare
Choose a tag to compare

Patch Changes

@xstate/vue@4.0.2

12 Jan 18:45
3b43d84
Compare
Choose a tag to compare

Patch Changes

@xstate/svelte@4.0.3

12 Jan 18:45
3b43d84
Compare
Choose a tag to compare

Patch Changes

@xstate/solid@1.0.2

12 Jan 18:45
3b43d84
Compare
Choose a tag to compare

Patch Changes

@xstate/react@5.0.2

12 Jan 18:45
3b43d84
Compare
Choose a tag to compare

Patch Changes

@xstate/graph@3.0.2

12 Jan 18:45
3b43d84
Compare
Choose a tag to compare

Patch Changes

xstate@5.19.1

24 Dec 19:13
e754939
Compare
Choose a tag to compare

Patch Changes

  • #5139 bf6119a7310a878afbf4f5b01f5e24288f9a0f16 Thanks @SandroMaglione! - Make spawn input required when defined inside referenced actor:

    const childMachine = createMachine({
      types: { input: {} as { value: number } }
    });
    
    const machine = createMachine({
      types: {} as { context: { ref: ActorRefFrom<typeof childMachine> } },
      context: ({ spawn }) => ({
        ref: spawn(
          childMachine,
          // Input is now required!
          { input: { value: 42 } }
        )
      })
    });