Package Exports
- @xstate/react
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (@xstate/react) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
XState React Tools
Quick Start
- Install
xstateand@xstate/react:
npm i xstate @xstate/react- Import the
useMachinehook:
import { useMachine } from '@xstate/react';
import { Machine } from 'xstate';
const toggleMachine = Machine({
id: 'toggle',
initial: 'inactive',
states: {
inactive: {
on: { TOGGLE: 'active' }
},
active: {
on: { TOGGLE: 'inactive' }
}
}
});
export const Toggler = () => {
const [current, send] = useMachine(toggleMachine);
return (
<button onClick={() => send('TOGGLE')}>
{current.value === 'inactive'
? 'Click to activate'
: 'Active! Click to deactivate'}
</button>
);
};API
useMachine(machine, options?)
A React hook that interprets the given machine and starts a service that runs for the lifetime of the component.
Arguments
machine- An XState machine.options(optional) - Interpreter options that you can pass in.
Returns a tuple of [current, send]:
current- Represents the current state of the machine as an XStateStateobject.send- A function that sends events to the running service.
Configuring Machines
Existing machines are configurable with .useConfig(...). The machine passed into useMachine will remain static for the entire lifetime of the component (it is important that state machines are the least dynamic part of the code).
Example: the 'fetchData' service and 'notifyChanged' action are both configurable:
const fetchMachine = Machine({
id: 'fetch',
initial: 'idle',
context: {
data: undefined
},
states: {
idle: {
on: { FETCH: 'loading' }
},
loading: {
invoke: {
src: 'fetchData',
onDone: {
target: 'success',
actions: assign({
data: (_, e) => e.data
})
}
}
},
success: {
onEntry: 'notifyResolve',
type: 'final'
}
}
});
const Fetcher = ({ onResolve }) => {
const [current, send] = useMachine(
fetchMachine.withContext({
actions: {
notifyResolve: ctx => {
onResolve(ctx.data);
}
},
services: {
fetchData: (ctx, e) =>
fetch(`some/api/${e.query}`).then(res => res.json())
}
})
);
switch (current.state) {
case 'idle':
return (
<button onClick={() => send({ type: 'FETCH', query: 'something' })}>
Search for something
</button>
);
case 'loading':
return <div>Searching...</div>;
case 'success':
return <div>Success! Data: {current.context.data}</div>;
default:
return null;
}
};Matching States
Using a switch statement might suffice for a simple, non-hierarchical state machine, but for hierarchical and parallel machines, the state values will be objects, not strings. In this case, it's better to use state.matches(...):
// ...
if (current.matches('idle')) {
return /* ... */;
} else if (current.matches({ loading: 'user' })) {
return /* ... */;
} else if (current.matches({ loading: 'friends' })) {
return /* ... */;
} else {
return null;
}