summaryrefslogtreecommitdiffstats
path: root/frontend/lib/withData.js
diff options
context:
space:
mode:
Diffstat (limited to 'frontend/lib/withData.js')
-rw-r--r--frontend/lib/withData.js76
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>
+ );
+ }
+ };