Last active
July 26, 2016 21:05
-
-
Save mLuby/9ee6b97ab099ec4c268ced1bcbebd032 to your computer and use it in GitHub Desktop.
Implementation of redux pattern and simulated use within a react-like app.
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
"use strict" | |
// Redux | |
const bindActionCreators = (actionCreator, dispatch) => args => dispatch(actionCreator(args)) | |
const createStore = reducer => { // (state -> action -> state) -> Store | |
let state = null | |
const subscribers = [] | |
const dispatch = action => { | |
state = reducer(state, action) | |
subscribers.forEach(cb => cb(state)) | |
} | |
const subscribe = callback => subscribers.push(callback) | |
const connect = (mapStateToProps, mapDispatchToProps, component) => { | |
subscribe(state => component.onNewState(mapStateToProps(state))) | |
return mapDispatchToProps(dispatch) | |
} | |
return { | |
dispatch, // action -> () | |
subscribe, // callback -> () | |
connect // (state -> props) -> (dispatch -> props) -> Component -> Component | |
} | |
} | |
// App | |
// action types | |
const INCREMENT_COUNTER = "INCREMENT_COUNTER" | |
const SET_COUNTER = "SET_COUNTER" | |
// action creators | |
const incrementCounter = () => ({type: INCREMENT_COUNTER}) | |
const setCounter = value => ({type: SET_COUNTER, payload: value}) | |
// reducers | |
const initialState = {counter: 0, counterIsOdd: false} | |
const isOdd = value => Boolean(value % 2) // helper function | |
const rootReducer = (state, action) => { | |
state = state || initialState | |
switch (action.type) { | |
case INCREMENT_COUNTER: return Object.assign({}, state, { | |
counter: state.counter + 1, | |
counterIsOdd: isOdd(state.counter + 1) | |
}) | |
case SET_COUNTER: return Object.assign({}, state, { | |
counter: action.payload, | |
counterIsOdd: isOdd(action.payload) | |
}) | |
default: return state | |
} | |
} | |
// Components | |
const store = createStore(rootReducer) | |
// Component A: click to increment counter; displays whether counter is odd. | |
const ComponentA = { | |
onNewState: newState => console.log('Component A received new state', newState), | |
onClick: () => store.dispatch(incrementCounter()) | |
} | |
store.subscribe(ComponentA.onNewState) | |
// Component B: input that displays counter value; can change counter. | |
const ComponentB = { | |
onNewState: newState => console.log('Component B received new state', newState), | |
onChange: value => setCounter(value) | |
} | |
const mapStateToPropsB = props => ({ | |
counter: props.counter | |
}) | |
const mapDispatchToPropsB = dispatch => ({ | |
onChange: bindActionCreators(ComponentB.onChange, dispatch) | |
}) | |
const HigherOrderComponentB = store.connect(mapStateToPropsB, mapDispatchToPropsB, ComponentB) | |
// Runtime/user interaction | |
ComponentA.onClick() | |
// Component A received new state { counter: 1, counterIsOdd: true } | |
// Component B received new state { counter: 1 } | |
HigherOrderComponentB.onChange(7) | |
// Component A received new state { counter: 7, counterIsOdd: true } | |
// Component B received new state { counter: 7 } | |
ComponentA.onClick() | |
// Component A received new state { counter: 8, counterIsOdd: false } | |
// Component B received new state { counter: 8 } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment