Pattern · 30
State machine
状态机 · state-machineGive opening and closing explicit states and allowed events so repeated clicks have predictable results.
A detail panel is not only open or closed; it is also opening or closing. A single boolean can let a new open arrive before a close animation finishes, creating two panels or letting an old callback overwrite current state. A state machine accepts only events allowed in the current state and ignores the rest.
Formula
idle + OPEN → opening opening + DONE → open open + CLOSE → closing closing + DONE → idle any undefined transition → ignore
Parameters
| This page | Mature libraries | |
|---|---|---|
| states | idle / opening / open / closing | — |
| events | OPEN / CLOSE / DONE | — |
| transition | only entries in the table | — |
Doing it well
- Use transition states to guard animation starts and ends. The
cardwalldetail code usesclosed/open/closingto reject mistimed opens and closes.www-motion/rewrite/cardwall/detail.js:4–7 - Put allowed events in a table; return failure for an unlisted event instead of silently toggling a boolean.www-motion/rewrite/cardwall/detail.js:4–7
- Treat animation completion as an event, valid only in its transition state, so an old completion cannot overwrite a newer state.www-motion/rewrite/cardwall/detail.js:4–7
In our cases
59 studies use explicit state control. cardwall guards detail opens and closes with phase; dimension separates vortex, burst, and chain phases so the same wheel input means different things in each phase.
Used in 59 cases
01Momentum Slider02Drag Gallery03Formation04Cardwall05Riffle07Rotunda08Iris10Frieze11Aperture13Cinema Reel14Stream Showcase15Hardback16Picasso Ecommerce17Assembly19Emulsion20Portfolio Photographer21Reverie22Boutique
+41 more
23Nova25Shape Trail27Liquid Type28Filament29Pixels30Cipher31Console32Cutout33Crema34Aster35Spring36Benchmark37Amour38Fluid Gallery39Marathon40Atelier41Desk 9542Isle43Pantheon44Atlas45Aurora46Rooster Rush47Overworld48Moments49Burst50Dimension51Morph54Lumen55Serene56Fleur59Helix60Crate61Prism62Flashlight63Viewfinder64Sand65Arrange66Tunnel67Reel68Type69Loupe
Reference implementation · basics.js
/** Explicit states and allowed transitions: events not listed for the current state are ignored. */
export function createMachine({ initial, states }, onChange = () => {}) {
let state = initial;
return {
get state() { return state; },
can: event => !!states[state]?.on?.[event],
send(event) {
const next = states[state]?.on?.[event];
if (!next) return false;
states[state].exit?.(); const prev = state; state = next; states[state].enter?.();
onChange(state, prev, event);
return true;
},
};
}