-
-
Save Slooowpoke/92121b3f438cce15a71e48ca8c9367b0 to your computer and use it in GitHub Desktop.
MST + Xstate
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* eslint-disable no-param-reassign */ | |
import { | |
getMembers, types | |
} from 'mobx-state-tree' | |
import { | |
createMachine | |
} from 'xstate' | |
import { interpret } from 'xstate/lib/interpreter' | |
// Pieced together from: | |
// https://github.com/mobxjs/mobx-state-tree/issues/1149 | |
export const createXStateStore = (definition: any, stores: any) => { | |
// Generate a configuration for xstate from store actions | |
const config = { | |
services: {}, | |
actions: {}, | |
guards: {}, | |
} | |
Object.keys(stores).forEach((storeKey) => { | |
const store = stores[storeKey]; | |
const members = getMembers(store); | |
const prefix = storeKey !== 'self' ? storeKey : null | |
members.actions.forEach((key) => { | |
const keyWithFirstPartRemoved = key.substring(key.indexOf('.') + 1); | |
const actionPath = prefix ? `${prefix}.${keyWithFirstPartRemoved}` : keyWithFirstPartRemoved | |
Object.keys(config).forEach((configKey) => { | |
if (key.includes(configKey)) { | |
config[configKey][actionPath] = store[key]; | |
} | |
}) | |
}) | |
// views translate to guards | |
members.views.forEach((key) => { | |
const viewPath = prefix ? `${prefix}.${key}` : key | |
config.guards[viewPath] = store[key]; | |
}) | |
}) | |
const machine = createMachine(definition, config) | |
const store = types | |
.model('xstate', { | |
machineDefinition: types.frozen(), | |
value: types.optional(types.frozen(), {}), | |
nextEvents: types.array(types.string) | |
}) | |
.volatile((self: any) => ({ | |
machine, | |
})) | |
.volatile((self: any) => ({ | |
currentState: machine.initialState, | |
})) | |
.volatile((self: any) => ({ | |
service: interpret(self.machine).onTransition((state) => { | |
self.setValue(state.value) | |
self.setNextEvents(state.nextEvents) | |
self.setCurrentState(state); | |
}), | |
})) | |
.views((self) => ({ | |
matches(stateString = '') { | |
return self.currentState.matches(stateString) | |
}, | |
})) | |
.actions((self: any) => ({ | |
setCurrentState(state) { | |
self.currentState = state | |
}, | |
setValue(value: string) { | |
self.value = value | |
}, | |
setNextEvents(nextEvents: any) { | |
self.nextEvents = nextEvents | |
}, | |
afterCreate() { | |
self.value = self.machine.initialState.value | |
self.currentState = self.machine.initialState; | |
self.service.start() | |
}, | |
send: self.service.send | |
})) | |
return store.create({ | |
machineDefinition: definition | |
}) | |
} | |
// Prefixes all the methods with their types 'actions.', 'guards.', 'services.' | |
export const convertActions = (actions, configKey) => { | |
const updatedActions = {} | |
Object.keys(actions).forEach((key) => { | |
updatedActions[`${configKey}.${key}`] = actions[key]; | |
}) | |
return updatedActions; | |
} | |
export const convertToXStateServices = (actions) => convertActions(actions, 'services') | |
export const convertToXStateActions = (actions) => convertActions(actions, 'actions') | |
// Elsewhere | |
// convert to xstate services | |
// .actions((self) => convertToXStateServices({ | |
// createSomething: flow(createSomething(self)), | |
// converted to actions | |
// .actions((self) => convertToXStateActions({ | |
// someAction: () => history.push(''), | |
// auto converted to xstate guards | |
// .views((self) => { | |
// someAction: () => history.push(''), | |
// And then -- | |
// .volatile((self) => ({ | |
// xstate: createXStateStore(SomeMachine, { | |
// self, | |
// nestedStore: self.nestedStore | |
// }) | |
// })) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment