Skip to content

Releases: statelyai/xstate

v4.3.3

26 Feb 14:15
Compare
Choose a tag to compare
  • 💻 Multiple services now are invoked as expected thanks to @tivac - #367, #368
  • 📅 Event object type inference improved. #338
  • 🆕 New StateNode method: .resolveState(state) returns a resolved state (with resolved state .value, .nextEvents, etc.) in relation to state node (machine):
// partial state
const someState = State.from('red', undefined);
const resolvedState = lightMachine.resolveState(someState);

resolvedState.value;
// => `{ red: 'walk' }`
  • 📦 Initial work on adding Lerna was started. Expect more tools in the future!
  • 🏞 Environment checks fixed thanks to @Andarist #371
    • This creates dist/xstate.web.js for use in browsers.

v4.3.2

13 Feb 14:57
Compare
Choose a tag to compare
  • 💥 This patch fixes #364 and #337 (related: #365) where the original event was not being persisted on state.event, leading to the wrong event being used in executing the actions on state.actions.

v4.3.1

29 Jan 16:46
Compare
Choose a tag to compare
  • 🏃‍♀️ This patch fixes an edge-case race condition where an invoked child service might send a done.state event before the parent service is done processing the event that invoked the service. #323

v4.3.0

27 Jan 18:38
Compare
Choose a tag to compare
  • 🚚 Improved import/export experience!

The interpreter is now included in the main module:

- import { interpret } from 'xstate/lib/interpreter';
+ import { interpret } from 'xstate';

As well as common actions, send, assign, and sendParent:

- import { actions } from 'xstate';
- const { send, assign, sendParent } = actions;
+ import { send, assign, sendParent } from 'xstate';

This change is reflected in the documentation as well as the tests.

  • ⚛️ Redux DevTools is now supported by XState. This can be turned off/on with the devTools property (true by default):
const service = interpret(someMachine, {
  devTools: false // don't show in Redux DevTools
});

ℹ️ Note: JUMP and SKIP actions in the DevTools will have no effect on XState, because there is no reliable way to arbitrarily go from one state to another with state machines, especially if side-effects are executed.

  • 👓 Better TypeScript inference for event types is now available thanks to @sangallimarco #303
  • 🏷 Service IDs will now take the ID of the machine if one is not specified:
const machine = Machine({ id: 'foo', /* ... */ });

// ...
{
  invoke: {
    // Invoked child service will have .id === 'foo'
    src: machine
  }
}

v4.2.4

13 Jan 19:40
Compare
Choose a tag to compare
  • 🕵️ Anonymous functions (including arrow functions) as actions are no longer silently ignored, and are executed. #298
  • 💥 New method on services: .execute(state) will execute the state's actions (defined on state.actions). #295
  • 📖 Documentation updates:
  • 🕐 State history is correctly disposed now, to prevent memory leaks.
  • ☎️ Second argument to invoked callbacks, onEvent, now let you register event listeners for when the machine sends events directly to the invoked callbacks. (docs coming 🔜)
  • 🚦 Activities are now properly disposed when a service is stopped.

v4.2.3

28 Dec 05:11
Compare
Choose a tag to compare
  • 🔢 Fix for the order property when one isn't defined in the machine config for a given state node.
  • 🔧 Small type fix for the StateListener (it should accept an event object, not an event)
  • 📞 Type fix for the service config property to allow specifying promises and callbacks as services. #285

v4.2.2

22 Dec 03:39
Compare
Choose a tag to compare

v4.2.1

06 Dec 11:44
Compare
Choose a tag to compare
  • 📚 Lots of documentation updates: https://xstate.js.org/docs
  • 💥 Added the .event property to State instances, so you can know which event caused the transition to the current State:
const lightMachine = Machine({ /* ... */ });

const currentState = lightMachine.transition('green', 'TIMER');

console.log(currentState.event);
// => { type: 'TIMER' }
  • 👪 Fixed #269 by ensuring two things:
    • Services invoked on the parent machine (which are alive for the lifetime of the machine, FYI) are successfully invoked when the machine is started
    • Starting activities (such as invoke, which is an activity) should be executed before executing onEntry actions.

v4.2.0

04 Dec 01:34
Compare
Choose a tag to compare
  • ➕ Added CODE_OF_CONDUCT.md
  • 💙 Added Webflow as a sponsor
  • 📖 Added documentation directly to the master branch for easier maintenance (in the /docs directory)
  • The send(...) action creator now accepts an "event expression", which is a function that provides context and event as arguments and returns an Event:
import { actions } from 'xstate';
const { send } = actions;

// contrived example
const sendName = send((ctx, event) => ({
  type: 'NAME',
  name: ctx.user.name
}));

Only use this when necessary - a static argument, e.g., send({ type: 'FOO' }) is still preferred (because it's more deterministic). This follows the <send> SCXML spec for the eventexpr attribute.

This also works with sendParent(eventExpr).

  • 🆕 Added the state.inert getter property on State instances, which represents a state as-is without actions.
  • #️⃣ Targets can now be represented as getters that return references to StateNodes rather than string IDs:
const lightMachine = Machine({
  // ...
  states: {
	green: {
	  on: {
		get TIMER() {
		  return lightMachine.states.yellow;
		}
	  }
    },
	yellow: { /* ... */ }
  }
});

This is completely optional, and useful when if you want to avoid strings or have stricter typings.

  • 🔧 Strict machines (strict: true) will no longer throw errors for built-in events, such as done.state.* or done.invoke.* events.
  • 📞 Now you can invoke a service that can send multiple events back to the parent via a callback:
// ...
states: {
  counting: {
	invoke: {
	  src: (ctx, event) => (callback) => {
		const interval = setInterval(() => {
		  // sends 'SOME_EVENT' to parent on interval
		  callback('SOME_EVENT');
		}, ctx.interval);

		return () => clearInterval(interval);
	  }
	}
  }
}
// ...

This makes it easy to communicate with streams of events (such as Observables) through invoke. Note that since there can be an infinite number of events, it's not assumed that a callback interval will call onDone. Instead, you have to manually send doneInvoke(id) via the callback (this will be in the docs 🔜).

  • ⛔️ An interpreted machine (service) will now throw an error if the initial state given to it is invalid.

v4.1.1

18 Nov 14:18
Compare
Choose a tag to compare
  • .npmignore was removed ❌
  • The "files" property was added instead to ensure only the desired files show up in the NPM package.