React
在React 中使用
Hooks
这裡我们使用
const LIGHT_STATES = {
RED: "RED",
GREEN: "green",
YELLOW: "yellow",
};
const LIGHT_EVENTS = {
CLICK: "CLICK",
};
export const lightMachine = Machine({
initial: LIGHT_STATES.RED,
states: {
[LIGHT_STATES.RED]: {
on: {
[LIGHT_EVENTS.CLICK]: LIGHT_STATES.GREEN,
},
},
[LIGHT_STATES.GREEN]: {
on: {
[LIGHT_EVENTS.CLICK]: LIGHT_STATES.YELLOW,
},
},
[LIGHT_STATES.YELLOW]: {
on: {
[LIGHT_EVENTS.CLICK]: LIGHT_STATES.RED,
},
},
},
});
然后在组件中定义状态:
import React from 'react';
import { useMachine } from '@xstate/react';
import { lightMachine } from './lightMachine';
function App() {
const [state, send] = useMachine(lightMachine);
return (
//...
);
}
import React from "react";
import { useMachine } from "@xstate/react";
import { lightMachine } from "./lightMachine";
function App() {
const [state, send] = useMachine(lightMachine);
return (
<div className="App">
{state.matches(LIGHT_STATES.RED) && <RedLight />}
{state.matches(LIGHT_STATES.GREEN) && <GreenLight />}
{state.matches(LIGHT_STATES.YELLOW) && <YellowLight />}
<button
onClick={() => {
send(LIGHT_EVENTS.CLICK);
}}
>
click me
</button>
</div>
);
}
最后
在类组件中使用
当然,我们也可以在类组件中使用,定义如下的状态机:
import { Machine } from "xstate";
// This machine is completely decoupled from React
export const toggleMachine = Machine({
id: "toggle",
initial: "inactive",
states: {
inactive: {
on: { TOGGLE: "active" },
},
active: {
on: { TOGGLE: "inactive" },
},
},
});
对状态机进行解释,并将其服务实例放在组件实例上。对于本地状态,
import React from "react";
import { Machine, interpret } from "xstate";
import { toggleMachine } from "../path/to/toggleMachine";
class Toggle extends React.Component {
state = {
current: toggleMachine.initialState,
};
service = interpret(toggleMachine).onTransition((current) =>
this.setState({ current })
);
componentDidMount() {
this.service.start();
}
componentWillUnmount() {
this.service.stop();
}
render() {
const { current } = this.state;
const { send } = this.service;
return (
<button onClick={() => send("TOGGLE")}>
{current.matches("inactive") ? "Off" : "On"}
</button>
);
}
}
更复杂的搜索的例子
import { Machine, assign } from "xstate";
import { search } from "../../services/github";
const statechart = {
id: "search",
context: {
result: [],
},
initial: "idle",
on: {
SEARCH: [
{
target: "searching",
cond: {
type: "search query has more than one character",
},
},
{
target: "idle",
actions: ["resetSearchResults"],
},
],
},
states: {
idle: {},
searching: {
invoke: {
src: "searchService",
onDone: {
target: "loaded",
actions: ["storeResult"],
},
onError: {
target: "failure",
},
},
},
loaded: {},
failure: {},
},
};
const machineConfig = {
services: {
searchService: (_, event) => {
return search(event.entity, {
q: event.q,
});
},
},
actions: {
storeResult: assign({
result: (_, event) => {
return event.data.items;
},
}),
resetSearchResults: assign({
result: () => {
return [];
},
}),
},
guards: {
"search query has more than one character": (_, event) => {
return event.q.length >= 2;
},
},
};
export const searchMachine = Machine(statechart, machineConfig);