Skip to content

Instantly share code, notes, and snippets.

@abhayarawal
Last active July 15, 2019 18:27
Show Gist options
  • Save abhayarawal/b26941c79739a756faa12bdc58403b9f to your computer and use it in GitHub Desktop.
Save abhayarawal/b26941c79739a756faa12bdc58403b9f to your computer and use it in GitHub Desktop.
react hooks with xstate and redux
import React, { useState, useEffect, useMemo, useReducer, useContext, useCallback } from 'react'
import { composeWithDevTools } from 'redux-devtools-extension'
import { createStore } from 'redux'
import { createSelector } from 'reselect'
import { Provider, shallowEqual, useSelector, useDispatch } from 'react-redux'
import { Machine, interpret, assign } from 'xstate'
import ReactDOM from 'react-dom'
const initialState = {
counter: 0
}
function reducer (state = initialState, action) {
switch (action.type) {
case 'increment':
let { counter } = state
counter += 1
return { ...state, counter }
default:
return state
}
}
const toggleMachine = Machine({
initial: 'inactive',
states: {
inactive: {
on: {
TOGGLE: 'active'
}
},
active: {
on: {
TOGGLE: 'inactive'
}
}
}
});
const useMachine = machine => {
const [state, setState] = useState(machine.initialState)
const service = useMemo(
() => {
return interpret(machine).onTransition(delta => {
if (delta.changed) {
setState(delta)
}
})
.start()
},
[]
)
useEffect(() => {
return () => {
service.stop()
}
}, [])
return [state, service.send]
}
const useInput = defaultValue => {
const [value, setValue] = useState(defaultValue)
return {
value: value,
setValue,
bind: {
value,
onChange: (e) => {
setValue(e.target.value)
}
}
}
}
const selectCounter = createSelector(
state => state.counter,
counter => counter
)
function Root () {
const counter = useSelector(selectCounter, shallowEqual)
const [machine, send] = useMachine(toggleMachine)
const dispatch = useDispatch()
const action = useCallback(
() => {
dispatch({type: 'increment'})
send('TOGGLE')
},
[dispatch])
return (
<div>
<div>{ counter }</div>
<button onClick={action}>Toggle - {machine.toStrings()[0]}</button>
</div>
)
}
const store = createStore(reducer, composeWithDevTools())
const $root = document.getElementById("react-root")
ReactDOM.render(<Provider store={store}><Root /></Provider>, $root)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment