Create your own react-redux connect
import React, { Component } from "react"; | |
import { render } from "react-dom"; | |
import Hello from "./Hello"; | |
import { createStore } from "redux"; | |
const shallowEqual = require("shallow-equal/objects"); | |
const store = createStore((oldState={}, action) => { | |
return Object.assign(oldState, { storeValue: action.storeValue }) | |
}); | |
function connect(mapStateToProps, mapDispatchToProps) { | |
return function(WrappedComponent) { | |
return class WrapperComponent extends Component { | |
constructor() { | |
super(); | |
this.state = { storeState: store.getState() }; | |
} | |
shouldComponentUpdate() { | |
// If the props to WrapperComponent do not change | |
// between setState calls, then we don't need to re-render. | |
// This operation below is known as a shallow comparison | |
const newProps = mapStateToProps(this.state.storeState, this.props); | |
return !shallowEqual(newProps, this.oldProps); | |
} | |
componentDidMount() { | |
this.unsubscribe = store.subscribe(() => { | |
this.setState({ storeState: store.getState() }); | |
}); | |
} | |
componentWillUnmount() { | |
this.unsubscribe(); | |
} | |
render() { | |
this.oldProps = mapStateToProps(this.state.storeState, this.props) | |
const newProps = Object.assign( | |
{}, | |
this.oldProps, | |
mapDispatchToProps(store.dispatch.bind(this)) | |
); | |
return <WrappedComponent {...newProps} />; | |
} | |
}; | |
}; | |
} | |
const App = ({storeValue}) => { | |
console.log("App is re-rendering"); | |
return ( | |
<div> | |
<h2>Store Value {storeValue}</h2> | |
</div> | |
); | |
}; | |
const NewApp = connect( | |
state => ({ | |
storeValue: state.storeValue | |
}), | |
() => ({}) | |
)(App); | |
class AppContainer extends Component { | |
constructor() { | |
super(); | |
this.state = { counter: 0 }; | |
} | |
//I suppose I could have used mapDispatch to props ¯\_(ツ)_/¯ | |
changeStore(e) { | |
store.dispatch({type: "CHANGE", storeValue: `${e.target.value}`}) | |
} | |
changeCounter() { | |
this.setState(oldState => ({ counter: ++oldState.counter })); | |
} | |
render() { | |
console.log("App Container is re-rendering") | |
return ( | |
<div> | |
{/*Changing the store will cause a re-render. Check the console to prove this to yourself. | |
Notice the store only update when leaving the input box's focus */} | |
<label>update store state</label> <input onBlur={this.changeStore.bind(this)} /> | |
{/*Notice that changing the parent of App never causes a re-render. Check the console to | |
prove this to yourself. */} | |
<button onClick={this.changeCounter.bind(this)}>update AppContainer state</button> | |
<span>{this.state.counter}</span> | |
<NewApp {...this.props} /> | |
</div> | |
); | |
} | |
} | |
render(<AppContainer />, document.getElementById("root")); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment