跳到主要内容

原理

2023年05月28日
柏拉文
越努力,越幸运

一、index.ts


import assign from "./assign";
import interpret from "./interpret";
import useMachine from "./useMachine";
import createMachine from "./createMachine";

export { createMachine, interpret, assign, useMachine };

二、assign.ts


function assign(assignment) {
return {
type: "assign",
assignment,
};
}

export default assign;

三、interpret.ts


const InterpretStatus = {
NotStarted: 0,
Running: 1,
Stopped: 2,
};

class Interpreter {
constructor(machine) {
this.machine = machine;
this.listeners = new Set();
this.status = InterpretStatus.NotStarted;
this.state = machine.states[machine.initial];
}
start = () => {
this.status = InterpretStatus.Running;
return this;
};
send = (event) => {
this.state = this.state.next(event);
this.listeners.forEach((listener) => listener(this.state));
return this;
};
onTransition = (listener) => {
this.listeners.add(listener);
return this;
};
}

function interpret(machine) {
return new Interpreter(machine);
}

export default interpret;

四、useMachine.ts


import { useState } from "react";
import interpret from "./interpret";

function useMachine(machine) {
const service = interpret(machine);
service.start();
let [, forceUpdate] = useState(0);
return [
service.state,
(event) => {
service.send(event);
forceUpdate((x) => x + 1);
},
];
}

export default useMachine;

五、createMachine.ts


class StateNode {
constructor(config, machine, value) {
this.config = config;
this.initial = config.initial;
this.value = value || config.initial;
this.machine = machine || this;
this.context = config.context || this.machine.context;
this.on = config.on;
let states = {};
if (config.states) {
for (let key in config.states) {
states[key] = new StateNode(config.states[key], this.machine, key);
}
}
this.states = states;
}
next = (event) => {
let { type } = event;
let nextState = this.on[type];
if (typeof nextState === "string") {
return this.getStateNode(nextState);
} else {
let actions = nextState.actions;
if (Array.isArray(actions)) {
let context = this.context;
let newContext = {};
actions.forEach((action) => {
let assignment = action.assignment;
for (let key in assignment) {
if (typeof assignment[key] === "function") {
newContext[key] = assignment[key](context, event);
} else {
newContext[key] = assignment[key];
}
}
});
Object.assign(context, newContext);
}
return this;
}
};
getStateNode = (stateKey) => {
return this.machine.states[stateKey];
};
}

function createMachine(config) {
return new StateNode(config);
}

export default createMachine;