Machines d'état et diagrammes d'état pour le Web moderne.
JavaScript et TypeScript finite state machines (opens new window) and statecharts (opens new window) pour le Web moderne.
Vous débutez avec les machines d'état et les diagrammes d'état ? Lire notre présentation.
🖥 Téléchargez notre extension VS Code (opens new window).
📑 Consulter la specification SCXML (opens new window)
💬 Collaborez avec la Communauté Stately sur Discord (opens new window)
# Packages
- 🤖
xstate
- Machine à états finis de base et bibliothèque de diagrammes d'états + interpréteur - 📉
@xstate/graph
(opens new window) - Graph traversal utilities for XState - ⚛️
@xstate/react
(opens new window) - Hooks et utilitaires React pour utiliser XState dans les applications React - 💚
@xstate/vue
(opens new window) - Fonctions et utilitaires de composition Vue.js pour utiliser XState dans les applications Vue.js - 🎷
@xstate/svelte
(opens new window) - Utilitaires Svelte pour utiliser XState dans les applications Svelte - ✅
@xstate/test
(opens new window) - Utilitaires de Test basés sur des modèles (utilisant XState) pour tester n'importe quel logiciel - 🔍
@xstate/inspect
(opens new window) - Utilitaires d'inspection pour XState
# Templates
Commencez par dupliquer l'un de ces modèles sur CodeSandbox :
- Modèle XState (opens new window) - sans framework
- Modèle XState + TypeScript (opens new window) - sans framework
- Modèle XState + React (opens new window)
- Modèle XState + React + TypeScript (opens new window)
- Modèle XState + Vue (opens new window)
- Modèle XState + Vue 3 (opens new window)
- Modèle XState + Svelte (opens new window)
# Démarrage ultra rapide
npm install xstate
import { createMachine, interpret } from 'xstate';
// Définition de machine
// machine.transition(...) est une fonction pure utilisée par l'interpréteur.
const toggleMachine = createMachine({
id: 'toggle',
initial: 'inactive',
states: {
inactive: {
on: {
TOGGLE: { target: 'active' }
}
},
active: {
on: {
TOGGLE: { target: 'inactive' }
}
}
}
});
// Instance de machine avec état interne
const toggleService = interpret(toggleMachine)
.onTransition((state) => console.log(state.value))
.start();
// => 'inactive'
toggleService.send({ type: 'TOGGLE' });
// => 'active'
toggleService.send({ type: 'TOGGLE' });
// => 'inactive'
# Exemple de promesse
📉 Visualiser sur stately.ai/viz (opens new window)
import { createMachine, interpret, assign } from 'xstate';
const fetchMachine = createMachine({
id: 'Dog API',
initial: 'idle',
context: {
dog: null
},
states: {
idle: {
on: {
FETCH: { target: 'loading' }
}
},
loading: {
invoke: {
id: 'fetchDog',
src: (context, event) =>
fetch('https://dog.ceo/api/breeds/image/random').then((data) =>
data.json()
),
onDone: {
target: 'resolved',
actions: assign({
dog: (_, event) => event.data
})
},
onError: {
target: 'rejected'
}
},
on: {
CANCEL: { target: 'idle' }
}
},
rejected: {
on: {
FETCH: { target: 'loading' }
}
},
resolved: {
type: 'final'
}
}
});
const dogService = interpret(fetchMachine)
.onTransition((state) => console.log(state.value))
.start();
dogService.send({ type: 'FETCH' });
- Visualiseur
- Pourquoi?
- Machine à états finis
- Machines avec états composés
- Machines avec états parallèles
- États d'historique
- Sponsors
# Visualiseur
Visualisez, simulez et partagez vos diagrammes d'états dans XState Viz ! (opens new window)
# Pourquoi ?
Un diagramme d'état est un formalisme permettant de modéliser des systèmes réactifs avec état. Ceci est utile pour décrire de manière déclarative le comportement de votre application, des composants individuels à la logique globale de l'application.
Lire 📽 les slides (opens new window) (🎥 vidéo (opens new window)) ou consultez ces ressources pour en savoir plus sur l'importance des machines à états finis et des diagrammes d'états dans les interfaces utilisateur :
- Statecharts - A Visual Formalism for Complex Systems (opens new window) par David Harel
- The World of Statecharts (opens new window) par Erik Mogensen
- Pure UI (opens new window) par Guillermo Rauch
- Pure UI Control (opens new window) par Adam Solove
- Spectrum - Statecharts Community (opens new window) (Pour les questions spécifiques à XState, veuillez utiliser les discussions sur Github (opens new window))
# Machines à états finis
import { createMachine } from 'xstate';
const lightMachine = createMachine({
id: 'light',
initial: 'green',
states: {
green: {
on: {
TIMER: { target: 'yellow' }
}
},
yellow: {
on: {
TIMER: { target: 'red' }
}
},
red: {
on: {
TIMER: { target: 'green' }
}
}
}
});
const currentState = 'green';
const nextState = lightMachine.transition(currentState, {
type: 'TIMER'
}).value;
// => 'yellow'
# Machines avec des états composés
import { createMachine } from 'xstate';
const pedestrianStates = {
initial: 'walk',
states: {
walk: {
on: {
PED_TIMER: { target: 'wait' }
}
},
wait: {
on: {
PED_TIMER: { target: 'stop' }
}
},
stop: {}
}
};
const lightMachine = createMachine({
id: 'light',
initial: 'green',
states: {
green: {
on: {
TIMER: { target: 'yellow' }
}
},
yellow: {
on: {
TIMER: { target: 'red' }
}
},
red: {
on: {
TIMER: { target: 'green' }
},
...pedestrianStates
}
}
});
const currentState = 'yellow';
const nextState = lightMachine.transition(currentState, {
type: 'TIMER'
}).value;
// => {
// red: 'walk'
// }
lightMachine.transition('red.walk', { type: 'PED_TIMER' }).value;
// => {
// red: 'wait'
// }
Notation d'objet pour les états composés:
// ...
const waitState = lightMachine.transition(
{ red: 'walk' },
{ type: 'PED_TIMER' }
).value;
// => { red: 'wait' }
lightMachine.transition(waitState, { type: 'PED_TIMER' }).value;
// => { red: 'stop' }
lightMachine.transition({ red: 'stop' }, { type: 'TIMER' }).value;
// => 'green'
# Machines avec des états parallèles
import { createMachine } from 'xstate';
const wordMachine = createMachine({
id: 'word',
type: 'parallel',
states: {
bold: {
initial: 'off',
states: {
on: {
on: {
TOGGLE_BOLD: { target: 'off' }
}
},
off: {
on: {
TOGGLE_BOLD: { target: 'on' }
}
}
}
},
underline: {
initial: 'off',
states: {
on: {
on: {
TOGGLE_UNDERLINE: { target: 'off' }
}
},
off: {
on: {
TOGGLE_UNDERLINE: { target: 'on' }
}
}
}
},
italics: {
initial: 'off',
states: {
on: {
on: {
TOGGLE_ITALICS: { target: 'off' }
}
},
off: {
on: {
TOGGLE_ITALICS: { target: 'on' }
}
}
}
},
list: {
initial: 'none',
states: {
none: {
on: {
BULLETS: { target: 'bullets' },
NUMBERS: { target: 'numbers' }
}
},
bullets: {
on: {
NONE: { target: 'none' },
NUMBERS: { target: 'numbers' }
}
},
numbers: {
on: {
BULLETS: { target: 'bullets' },
NONE: { target: 'none' }
}
}
}
}
}
});
const boldState = wordMachine.transition('bold.off', {
type: 'TOGGLE_BOLD'
}).value;
// {
// bold: 'on',
// italics: 'off',
// underline: 'off',
// list: 'none'
// }
const nextState = wordMachine.transition(
{
bold: 'off',
italics: 'off',
underline: 'on',
list: 'bullets'
},
{ type: 'TOGGLE_ITALICS' }
).value;
// {
// bold: 'off',
// italics: 'on',
// underline: 'on',
// list: 'bullets'
// }
# États d'historique
import { createMachine } from 'xstate';
const paymentMachine = createMachine({
id: 'payment',
initial: 'method',
states: {
method: {
initial: 'cash',
states: {
cash: {
on: {
SWITCH_CHECK: { target: 'check' }
}
},
check: {
on: {
SWITCH_CASH: { target: 'cash' }
}
},
hist: { type: 'history' }
},
on: {
NEXT: { target: 'review' }
}
},
review: {
on: {
PREVIOUS: { target: 'method.hist' }
}
}
}
});
const checkState = paymentMachine.transition('method.cash', {
type: 'SWITCH_CHECK'
});
// => State {
// value: { method: 'check' },
// history: State { ... }
// }
const reviewState = paymentMachine.transition(checkState, { type: 'NEXT' });
// => State {
// value: 'review',
// history: State { ... }
// }
const previousState = paymentMachine.transition(reviewState, {
type: 'PREVIOUS'
}).value;
// => { method: 'check' }
# Sponsors
Un grand merci aux entreprises suivantes pour avoir parrainé xstate
. Vous pouvez parrainer d'autres développements de xstate
sur OpenCollective (opens new window).