Last active
August 29, 2018 17:45
-
-
Save mehiel/e1370b887a6acfc181864a7c81b444b0 to your computer and use it in GitHub Desktop.
Thinking on a FluxComponent
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
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 |
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
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