diff options
Diffstat (limited to 'frontend/lib/withData.js')
| -rw-r--r-- | frontend/lib/withData.js | 76 |
1 files changed, 76 insertions, 0 deletions
diff --git a/frontend/lib/withData.js b/frontend/lib/withData.js new file mode 100644 index 0000000..0c68f49 --- /dev/null +++ b/frontend/lib/withData.js @@ -0,0 +1,76 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { ApolloProvider, getDataFromTree } from 'react-apollo'; +import Head from 'next/head'; +import initApollo from './initApollo'; + +// Gets the display name of a JSX component for dev tools +function getComponentDisplayName(Component) { + return Component.displayName || Component.name || 'Unknown'; +} + +export default ComposedComponent => + class WithData extends React.Component { + static displayName = `WithData(${getComponentDisplayName(ComposedComponent)})`; + static propTypes = { + serverState: PropTypes.object.isRequired, + }; + + static async getInitialProps(ctx) { + let serverState = { apollo: {} }; + + // Evaluate the composed component's getInitialProps() + let composedInitialProps = {}; + if (ComposedComponent.getInitialProps) { + composedInitialProps = await ComposedComponent.getInitialProps(ctx); + } + + // Run all GraphQL queries in the component tree + // and extract the resulting data + if (!process.browser) { + const apollo = initApollo(); + // Provide the `url` prop data in case a GraphQL query uses it + const url = { query: ctx.query, pathname: ctx.pathname }; + try { + // Run all GraphQL queries + await getDataFromTree( + <ApolloProvider client={apollo}> + <ComposedComponent url={url} {...composedInitialProps} /> + </ApolloProvider> + ); + } catch (error) { + // Prevent Apollo Client GraphQL errors from crashing SSR. + // Handle them in components via the data.error prop: + // http://dev.apollodata.com/react/api-queries.html#graphql-query-data-error + } + // getDataFromTree does not call componentWillUnmount + // head side effect therefore need to be cleared manually + Head.rewind(); + + // Extract query data from the Apollo store + serverState = { + apollo: { + data: apollo.cache.extract(), + }, + }; + } + + return { + serverState, + ...composedInitialProps, + }; + } + + constructor(props) { + super(props); + this.apollo = initApollo(this.props.serverState.apollo.data); + } + + render() { + return ( + <ApolloProvider client={this.apollo}> + <ComposedComponent {...this.props} /> + </ApolloProvider> + ); + } + }; |
