Skip to content

Instantly share code, notes, and snippets.

@mehiel
Last active August 29, 2018 17:45
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mehiel/e1370b887a6acfc181864a7c81b444b0 to your computer and use it in GitHub Desktop.
Save mehiel/e1370b887a6acfc181864a7c81b444b0 to your computer and use it in GitHub Desktop.
Thinking on a FluxComponent
import { Component } from 'react'
import propOr from 'ramda/src/propOr'
import identity from 'ramda/src/identity'
import map from 'ramda/src/map'
import compose from 'ramda/src/compose'
class FluxComponent extends Component {
static createReducer = (initialState, handlers) => (state = {}, action) =>
propOr(identity, action.type, handlers)(state, action)
static bindActionCreators = (dispatch, actionCreators) => typeof actionCreators === 'function'
? compose(dispatch, actionCreators)
: map(actionCreator => compose(dispatch, actionCreator), actionCreators)
constructor (props, handlers = {}, middlewares = []) {
super(props)
const reducer = FluxComponent.createReducer(this.state, handlers)
const dispatch = (action) => this.setState((state, props) => reducer(state, action, props))
const middlewareAPI = {
getState: () => this.getState(),
dispatch: (...args) => dispatch(...args)
}
const middlewareChain = middlewares.map(middleware => middleware(middlewareAPI))
this.dispatch = compose(...middlewareChain)(dispatch)
}
getState () {
return this.state
}
}
export default FluxComponent
import React from 'react'
import FluxComponent from './FluxComponent'
const fakeFetch = () => new Promise(resolve => setTimeout(() => resolve(42), 500))
const thunk = store => next => action =>
typeof action === 'function'
? action(store.dispatch, store.getState)
: next(action)
class FluxCounter extends FluxComponent {
static initialState = { loading: false, errors: null, counter: 0 }
static middlewares = [ thunk ]
static handlers = {
'COUNTER_RESET': (state, { payload }) => FluxCounter.initialState,
'FETCH_PENDING': (state) => ({ ...state, loading: true }),
'FETCH_FAILURE': (state, { payload }) => ({ ...state, loading: false, errors: payload }),
'FETCH_SUCCESS': (state, { payload }) => ({ ...state, loading: false, errors: null, counter: payload }),
'COUNTER_SET': (state, { payload }) => ({ ...state, counter: payload }),
'COUNTER_INC': (state) => ({ ...state, counter: state.counter + 1 }),
'COUNTER_DEC': (state) => ({ ...state, counter: state.counter - 1 }),
}
static actions = {
counterReset: values => ({ type: 'COUNTER_RESET' }),
fetchPending: () => ({ type: 'FETCH_PENDING' }),
fetchSuccess: (data) => ({ type: 'FETCH_SUCCESS', payload: data }),
fetchFailure: (errors) => ({ type: 'FETCH_FAILURE', payload: errors }),
fetchCounterValue: (values) => dispatch => {
const { fetchPending, fetchSuccess, fetchFailure } = FluxCounter.actions
dispatch(fetchPending())
fakeFetch('/api/counterValue')
.then(response => dispatch(fetchSuccess(response)))
.catch(errors => dispatch(fetchFailure(errors)))
},
counterSet: (data) => ({ type: 'COUNTER_SET', payload: data }),
counterInc: () => ({ type: 'COUNTER_INC' }),
counterDec: () => ({ type: 'COUNTER_DEC' }),
}
state = FluxCounter.initialState
constructor (props) {
super(props, FluxCounter.handlers, FluxCounter.middlewares)
this.actions = FluxComponent.bindActionCreators(this.dispatch, FluxCounter.actions)
}
onReset = (ev) => this.actions.counterReset()
onInc = (ev) => this.actions.counterInc()
onDec = (ev) => this.actions.counterDec()
onSet = (ev) => this.actions.counterSet(ev.target.value)
onFetchValue = (ev) => this.actions.fetchCounterValue()
render () {
const { loading, counter } = this.state
return (
<div>
<h2>Current Counter Value: {loading ? 'loading...' : counter}</h2>
<hr/>
<div>
Set counter value: <input type="number" onChange={this.onSet} value={counter} />
<br/><br/>
Step counter: <button onClick={this.onInc}>+</button> <button onClick={this.onDec}>-</button>
<br/><br/>
Get value from server: <button onClick={this.onFetchValue}>Load Value</button>
</div>
</div>
)
}
}
export default FluxCounter
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment