react-redux-pledge
Version:
Enhance your connected component by rendering them only when their props are guaranteed
114 lines (103 loc) • 3.82 kB
JavaScript
import React from 'react'
import { connect } from 'react-redux'
import createEagerFactory from 'recompose/createEagerFactory'
import renderComponent from 'recompose/renderComponent'
import shallowEqual from 'recompose/shallowEqual'
import {
find as _find,
includes as _includes,
isequal as _isequal
} from 'lodash'
import createPledgeAction from './createPledgeAction'
const withPledges = (pledges, loading) => BaseComponent => {
let resolvingPledges = []
class PledgeContainer extends React.Component {
constructor(props, context) {
super(props, context)
}
handlePledges(props) {
if (resolvingPledges.length == 0) {
this.componentFactory = this.componentFactory || createEagerFactory(BaseComponent)
this.factory = this.componentFactory
}
else {
this.loadingFactory = this.loadingFactory || createEagerFactory(
renderComponent(loading)(BaseComponent)
)
this.factory = this.loadingFactory
if (props.needResolving) {
props.resolvePledges()
}
}
}
componentWillMount() {
this.handlePledges(this.props)
}
componentWillReceiveProps(nextProps) {
this.handlePledges(nextProps)
}
render() {
return this.factory(this.props)
}
}
PledgeContainer.contextTypes = {
store: React.PropTypes.object
}
PledgeContainer.propTypes = {
store: React.PropTypes.object
}
return connect(
(_, initialProps) => (state) => {
let pledgesToResolve = []
for (let pledgesArray of pledges) {
if (pledgesToResolve.length == 0) {
for (let pledge of pledgesArray) {
pledge = typeof pledge === "function" ? pledge(state, initialProps) : pledge
if (!pledge.isResolved(state)) {
pledgesToResolve.push(pledge)
}
}
}
}
return { pledgesToResolve }
},
null,
(stateProps, dispatchProps, ownProps) => {
const { dispatch } = dispatchProps
const { pledgesToResolve } = stateProps
if (pledgesToResolve.length == 0) {
resolvingPledges = []
return {
...ownProps,
...stateProps,
...dispatchProps
}
}
let actions = []
/*
1): all pledges to resolve not already resolving need to be added to
the resolvingPledges array and their action to be pushed to the
actions array
2): resolving pledges that are not in pledgesToResolve anymore need
to be removed from resolvingPledges array.
*/
for (let pledge of pledgesToResolve) {
if (typeof _find(resolvingPledges, (name) => name === pledge.name) === "undefined") {
resolvingPledges.push(pledge.name)
actions.push(pledge.getAction())
}
}
resolvingPledges = resolvingPledges.filter(name => _includes(pledgesToResolve.map(p => p.name), name))
return {
...ownProps,
...stateProps,
...dispatchProps,
needResolving: actions.length > 0,
resolvePledges() {
dispatch(createPledgeAction(actions))
}
}
}
)(PledgeContainer)
}
export default withPledges