Last active
December 14, 2016 21:37
-
-
Save davidbalbert/65cc0486f3dffc7d6ed8ee489d8a647f to your computer and use it in GitHub Desktop.
mini redux
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
| // Redux | |
| function createStore(reducer) { | |
| let state; | |
| let listeners = []; | |
| const store = { | |
| dispatch(action) { | |
| state = reducer(state, action); | |
| for (let l of listeners) { | |
| l(); | |
| } | |
| }, | |
| getReducer() { | |
| return reducer; | |
| }, | |
| getState() { | |
| return state; | |
| }, | |
| replaceReducer(newReducer) { | |
| reducer = newReducer; | |
| }, | |
| subscribe(listener) { | |
| listeners.push(listener); | |
| } | |
| }; | |
| store.dispatch({type: "@@redux/INIT"}); | |
| return store; | |
| } | |
| // ReactRedux | |
| const { Component, PropTypes } = React; | |
| class Provider extends Component { | |
| static propTypes = { | |
| store: PropTypes.object.isRequired | |
| }; | |
| static childContextTypes = { | |
| store: PropTypes.object | |
| }; | |
| componentDidMount() { | |
| this.props.store.subscribe(this.storeChanged); | |
| } | |
| getChildContext() { | |
| return {store: this.props.store}; | |
| } | |
| storeChanged = () => { | |
| this.forceUpdate(); | |
| } | |
| render() { | |
| return this.props.children; | |
| } | |
| } | |
| function connect(mapStateToProps, mapDispatchToProps) { | |
| return WrappedComponent => { | |
| class Connected extends Component { | |
| static contextTypes = { | |
| store: PropTypes.object | |
| }; | |
| static WrappedComponent = WrappedComponent; | |
| static name = `Connect(${WrappedComponent.name})`; | |
| render() { | |
| const { store } = this.context; | |
| let props = {}; | |
| let dispatchProps = {}; | |
| if (mapStateToProps) { | |
| props = mapStateToProps(store.getState()); | |
| } | |
| if (mapDispatchToProps) { | |
| dispatchProps = mapDispatchToProps(store.dispatch); | |
| } | |
| return <WrappedComponent { ...props } { ...dispatchProps } dispatch={ store.dispatch } />; | |
| } | |
| } | |
| return Connected; | |
| }; | |
| } | |
| // The app | |
| const Actions = { | |
| inc() { | |
| return { | |
| type: "INC" | |
| }; | |
| }, | |
| dec() { | |
| return { | |
| type: "DEC" | |
| }; | |
| } | |
| }; | |
| @connect(state => state) | |
| class Counter extends Component { | |
| static propTypes = { | |
| count: PropTypes.number.isRequired, | |
| }; | |
| static contextTypes = { | |
| store: PropTypes.object, | |
| }; | |
| inc = () => { | |
| this.context.store.dispatch(Actions.inc()); | |
| } | |
| dec = () => { | |
| this.context.store.dispatch(Actions.dec()); | |
| } | |
| render() { | |
| return ( | |
| <div> | |
| {this.props.count} | |
| <button onClick={ this.inc }>+1</button> | |
| <button onClick={ this.dec }>-1</button> | |
| </div> | |
| ); | |
| } | |
| } | |
| const initialState = { | |
| count: 0, | |
| } | |
| function reducer(state = initialState, action) { | |
| switch (action.type) { | |
| case "INC": | |
| return { count: state.count + 1 }; | |
| case "DEC": | |
| return { count: state.count - 1 }; | |
| default: | |
| console.warn(`Unknown action type: ${action.type}`) | |
| return state; | |
| } | |
| } | |
| const store = createStore(reducer); | |
| ReactDOM.render( | |
| <Provider store={ store }><Counter /></Provider>, | |
| document.getElementById('app') | |
| ); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment