Last active
February 15, 2017 16:11
-
-
Save dlebedynskyi/575cc138c57af6b47f7c3f917b1f57f4 to your computer and use it in GitHub Desktop.
Prefetch
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const hoc = compose( | |
connect(mapStateToProps, mapDispatchToProps), | |
prefetch({ | |
fetch: ({pathname, load, hasLoaded}) => | |
(hasLoaded ? Promise.resolve() : load(pathname)), | |
defer: ({ | |
doSecureClientAPICallOne, | |
doSecureClientAPICallTwo | |
}) => [doSecureClientAPICall(), doSecureClientAPICallTwo()] | |
}), | |
pure); | |
const Test = ({somedata, hasLoaded, otherDataFromDefer}) => (...) | |
export default hoc(Test); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, {Component, PropTypes} from 'react'; | |
/** | |
* High order Component to request data load before rendering | |
* Has 2 props as params - fetch and defer. | |
* fetch - will be called both on client and server. | |
* It is your responsibility to make only server call or both. | |
* defer - will be called only on client side. | |
* @param {Promise|array[Promise]} fetch - promise(s) to resolve on server and client | |
* @param {Promise|array[Promise]} defer - promise(s) to resolve on client | |
*/ | |
const hoc = ({fetch, defer}) => WrappedCompontent => | |
class Prefetch extends Component { | |
static contextTypes = { | |
store: PropTypes.object, // Redux store. | |
serverFetchPromises: PropTypes.array | |
}; | |
displayName = 'Prefetch'; | |
constructor(props, context) { | |
super(props, context); | |
const {serverFetchPromises, store} = context; | |
// only server should set serverFetchPromises | |
// if this one exists then we fetch will called twice | |
if (serverFetchPromises && typeof fetch === 'function') { | |
const all = [].concat(fetch(props, store)); | |
all.forEach(p => p && serverFetchPromises.push(p)); | |
} | |
} | |
componentDidMount() { | |
const {serverFetchPromises, store} = this.context; | |
const promises = serverFetchPromises || []; | |
// making sure promises are resolved | |
// so call fetch again on client side, since server may fail some | |
if (typeof fetch === 'function') { | |
const all = [].concat(fetch(this.props, store)); | |
all.forEach(p => p && promises.push(p)); | |
} | |
// only client call data will happen. | |
// still going to add to general collection for consistency | |
if (typeof defer === 'function') { | |
const all = [].concat(defer(this.props, store)); | |
all.forEach(p => p && promises.push(p)); | |
} | |
} | |
render() { | |
return (<WrappedCompontent {...this.props}/>); | |
} | |
}; | |
hoc.propTypes = { | |
fetch: React.PropTypes.func, | |
defer: React.PropTypes.func | |
}; | |
export default hoc; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// server render method | |
const promises = []; | |
<Provider store={store}> | |
<ServerFetchProvider promises={promises}> | |
{/* rest of stuff*/} | |
</ServerFetchProvider> | |
</Provider> | |
if (promises.length > 0) { | |
await awaitForAll(fetchPromises); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from 'react'; | |
/** | |
* Server only Provider component that passes promises as context | |
*/ | |
export default class ServerFetchProvider extends React.Component { | |
static childContextTypes = { | |
serverFetchPromises: React.PropTypes.array | |
}; | |
static propTypes = { | |
children: React.PropTypes.node, | |
promises: React.PropTypes.array.isRequired | |
}; | |
getChildContext() { | |
return { | |
serverFetchPromises: this.props.promises | |
}; | |
} | |
render() { | |
return React.Children.only(this.props.children); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment