Skip to content

Instantly share code, notes, and snippets.

@killtheliterate
Last active June 13, 2018 20:34
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 killtheliterate/b45776ab122c5be16a236d3b48154355 to your computer and use it in GitHub Desktop.
Save killtheliterate/b45776ab122c5be16a236d3b48154355 to your computer and use it in GitHub Desktop.
A HOC for fetching data
// @see: https://gist.github.com/bvaughn/982ab689a41097237f6e9860db7ca8d6
import * as React from 'react'
// ---------------------------------------------------------------------------
export type EffOptions = {
StateComponent?: React.ComponentType<any>
}
export type EffProps = {
effect: () => Promise<any>
onError: (err: Error) => void
shouldEffectKey: string
}
export type EffState = {
isResolved: boolean
prevKey?: string
}
export function withEffect ({ StateComponent }: EffOptions) {
return function <P> (CC: React.ComponentType<P>) {
const IsEff: React.SFC<{}> = () => StateComponent
? (<StateComponent />)
: (<div>...loading</div>)
return class Eff extends React.Component<P & EffProps, EffState> {
_resolvingKey: string | void = undefined
state = {
isResolved: false,
prevKey: undefined
}
static getDerivedStateFromProps (nextProps: P & EffProps, prevState: EffState) {
if (nextProps.shouldEffectKey !== prevState.prevKey) {
return {
isResolved: false,
prevKey: nextProps.shouldEffectKey
}
}
return null
}
componentDidMount () {
this._effect(this.props.shouldEffectKey)
}
componentWillUnmount () {
this._resolvingKey = undefined
}
componentDidUpdate () {
if (this.state.isResolved === false) {
this._effect(this.props.shouldEffectKey)
}
}
render () {
const { effect, shouldEffectKey, onError, ...restProps } = this.props as EffProps
return this.state.isResolved
? (<CC {...restProps}/>)
: (<IsEff />)
}
// ---------------------------------------------------------------------
_effect = (key: EffProps['shouldEffectKey']) => {
if (key === this._resolvingKey) {
return // already resolving
}
this._resolvingKey = key
this.props.effect()
.then(
() => {
if (key === this._resolvingKey) {
this.setState(() => ({ isResolved: true }))
}
},
(err: Error) => {
if (key === this._resolvingKey) {
this.setState(() => ({ isResolved: true }))
this.props.onError(err)
}
}
)
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment