Skip to content

Instantly share code, notes, and snippets.

@ShMcK
Last active May 24, 2018 03:20
Show Gist options
  • Save ShMcK/052424e9dbcebb903affd8f3904064cf to your computer and use it in GitHub Desktop.
Save ShMcK/052424e9dbcebb903affd8f3904064cf to your computer and use it in GitHub Desktop.
React XState Context API wrapper
import React from 'react'
const capitalize = (string) => string.charAt(0).toUpperCase() + string.slice(1)
// lib, returns Context.Provider, Context.
function reactXState ({ name, machine, actions }) {
name = name || 'defaultName'
const Context = React.createContext(name)
class Provider extends React.Component {
static displayName = `${capitalize(name)}Provider`
constructor(props) {
super(props)
this.state = {
value: machine.initialStateValue,
}
this.actions = actions ? actions(this.dispatch) : {}
}
dispatch = (event) => {
const nextState = machine.transition(this.state.value, event)
for (const actionKey of nextState.actions) {
const action = this.actions[actionKey]
if (action) {
action(event)
}
}
switch(typeof nextState.value) {
// handle parallel or nested states
case 'object':
const value = {}
const transitions = []
for (const stateKey of Object.keys(nextState.value)) {
value[stateKey] = nextState.value[stateKey]
if (machine.states[nextState.value[stateKey].on]) {
transitions.push(machine.states[nextState.value[stateKey].on])
}
}
this.setState({ value, transitions })
break
default:
// handle default state
this.setState({
value: nextState.value,
transitions: machine.states[nextState.value].on
})
}
}
render() {
const value = {
dispatch: this.dispatch,
...this.state,
}
return (
<Context.Provider value={value}>
{this.props.children}
</Context.Provider>
)
}
}
return {
Consumer: Context.Consumer,
Provider,
}
}
// ---------------------------
import { Machine } from 'xstate'
const fetchActions = (dispatch) => {
let requestTimeout
return {
onRequestCancel() {
clearTimeout(requestTimeout)
},
onRequest(event, value) {
requestTimeout = setTimeout(() => {
dispatch('FAILURE')
}, 3000)
}
}
}
const machine = Machine({
key: 'fetch',
initial: 'idle',
states: {
idle: {
on: {
REQUEST: 'pending',
},
},
pending: {
on: {
SUCCESS: 'idle',
FAILURE: 'rejected',
CANCEL: {
idle: {
actions: ['onRequestCancel']
}
}
},
onEntry: 'onRequest',
},
rejected: {
on: {
RETRY: 'pending',
}
},
}
})
export default reactXState({ name: 'fetch', machine, actions: fetchActions })
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment