Juin Chiu
2 min readNov 8, 2016

ref: rect-redux/src/components/connect.js, React Redux with Dan Abramov

What does React-Redux do?

React-Redux is a library that provides bindings to React components for Redux. For example:

class Foo extends Component {
// ...
}

const mapStateToProps = (state) => {
return {
foo: state.foo,
bar: state.bar
}
}

const mapDispatchToProps = (dispatch) => {
return {
foo_plus_one: () => dispatch({type: 'foo_plus_one'})
}
}

export default connect(
mapStateToProps,
mapDispatchToProps
)(Foo)

What connect does is basically extracting state and dispatch actions from store, and wrapping them as props of wrapped component (i.e Foo in the above example). How can this be done? Let’s take a look on connect source code.

How does connect work?

// connect.js
export default function connect(mapStateToProps, mapDispatchToProps, mergeProps, options = {}) {
// ...
return function wrapWithConnect(WrappedComponent) {
// ...
class Connect extends Component {
// ...
trySubscribe() {
if (shouldSubscribe && !this.unsubscribe) {
this.unsubscribe = this.store.subscribe(this.handleChange.bind(this))
this.handleChange()
}
}

tryUnsubscribe() {
if (this.unsubscribe) {
this.unsubscribe()
this.unsubscribe = null
}
}

componentDidMount() {
this.trySubscribe()
}

componentWillUnmount() {
this.tryUnsubscribe()
this.clearCache()
}

handleChange() {
if (!this.unsubscribe) {
return
}

const storeState = this.store.getState()
const prevStoreState = this.state.storeState
if (pure && prevStoreState === storeState) {
return
}

if (pure && !this.doStatePropsDependOnOwnProps) {
const haveStatePropsChanged = tryCatch(this.updateStatePropsIfNeeded, this)
if (!haveStatePropsChanged) {
return
}
if (haveStatePropsChanged === errorObject) {
this.statePropsPrecalculationError = errorObject.value
}
this.haveStatePropsBeenPrecalculated = true
}

this.hasStoreStateChanged = true
this.setState({ storeState })
}

render() {
// ...
if (!haveMergedPropsChanged && renderedElement) {
return renderedElement
}

if (withRef) {
this.renderedElement = createElement(WrappedComponent, {
...this.mergedProps,
ref: 'wrappedInstance'
})
} else {
this.renderedElement = createElement(WrappedComponent,
this.mergedProps
)
}

return this.renderedElement
}
}
// ...
return hoistStatics(Connect, WrappedComponent)
}
}

connect is a curried function, which means it return a function. This returned function takes WrappedComponent as input, and returns a new React component Connect. Inside Connect component, the logic related to the store is handled. Connect component will finally render a new react element which is created from WrappedComponent.

What I ignored here are mostly some optimizations for rendering speed.

Juin Chiu
Juin Chiu

Written by Juin Chiu

Blockchain researcher, dev, co-organizer of Taipei Ethereum Meetup, focusing on consensus protocol, self-sovereign identity and anonymity network.

Responses (1)