Last active
May 24, 2018 03:20
-
-
Save ShMcK/052424e9dbcebb903affd8f3904064cf to your computer and use it in GitHub Desktop.
React XState Context API wrapper
This file contains hidden or 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
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