Skip to content

Instantly share code, notes, and snippets.

@crobinson42
Created June 7, 2019 22:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save crobinson42/63618ff183e56c33c1e1e80797f8ed3b to your computer and use it in GitHub Desktop.
Save crobinson42/63618ff183e56c33c1e1e80797f8ed3b to your computer and use it in GitHub Desktop.
JS-data React HOC
/* eslint-disable react/no-multi-comp, react/prop-types */
import React from 'react'
import hoistNonReactStatic from 'hoist-non-react-statics'
import shallowEqual from '../utils/shallowEqual'
function ConnectModelsHOC({ loadingProp, modelName, modelNames }, mapPropsWithModels) {
return WrappedComponent => {
class ConnectModels extends React.Component {
static contextType = ''
constructor(props) {
super(props)
this.state = {
propsToPass: {},
}
if (Array.isArray(modelNames)) {
this.models = modelNames.map(name => store[name])
this.modelsByName = modelNames.reduce((acc, name) => {
acc[name] = store[name]
return acc
}, {})
} else if (modelName) {
this.models = [store[modelName]]
} else {
this.models = []
}
this.promise = undefined
this.computeProps()
}
componentDidMount() {
this.models.forEach(model => model.on('change', this.computeProps))
}
componentDidUpdate(prevProps) {
if (!shallowEqual(prevProps, this.props)) this.computeProps()
}
componentWillUnmount() {
this.models.forEach(model => model.off('change', this.computeProps))
}
computeProps = () => {
if (this.promise) return
const mapPropsWithModelsValue = mapPropsWithModels(
this.modelsByName || this.models[0],
this.props,
)
if (mapPropsWithModelsValue && mapPropsWithModelsValue.then)
this.promise = mapPropsWithModelsValue
if (this.promise) {
this.promise.then(propsToPass => {
this.promise = undefined
this.setState({
propsToPass,
})
})
} else if (mapPropsWithModelsValue) {
this.setState({
propsToPass: mapPropsWithModelsValue,
})
}
}
render() {
const newObj = {}
if (loadingProp) newObj[loadingProp] = Boolean(this.promise)
const props = Object.assign(newObj, this.props, this.state.propsToPass)
return <WrappedComponent ref={this.props.forwardedRef} {...props} />
}
}
ConnectModels.displayName = `ConnectModels(${WrappedComponent.displayName ||
WrappedComponent.name ||
'Component'})`
hoistNonReactStatic(ConnectModels, WrappedComponent)
return React.forwardRef((props, ref) => <ConnectModels forwardedRef={ref} {...props} />)
}
}
export default ConnectModelsHOC
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment