diff --git a/app/providers/with-data.js b/app/providers/with-data.js
index 0ab9b3b..286009c 100644
--- a/app/providers/with-data.js
+++ b/app/providers/with-data.js
@@ -1,120 +1,74 @@
import 'cross-fetch/polyfill'
-import { Component } from 'react'
+import React, { Component } from 'react'
+import getDisplayName from 'react-display-name'
import { ApolloClient } from 'apollo-client'
import { InMemoryCache } from 'apollo-cache-inmemory'
import { createUploadLink } from 'apollo-upload-client'
import { getDataFromTree, ApolloProvider } from 'react-apollo'
-import getDisplayName from 'react-display-name'
-import Head from 'next/head'
+import { Router } from 'next/router'
+import App from 'next/app'
-const ssrMode = !process.browser
+// Shares the browser ApolloClient instance between pages.
+let browserApolloClient
-// To share an instance between pages on the client
-let apolloClient
-
-/**
- * Creates a new Apollo Client instance.
- * @param {Object} [initialState] - Redux initial state.
- * @returns {Object} Apollo Client instance.
- */
-const createApolloClient = (initialState = {}) =>
+const createApolloClient = (cache = {}) =>
new ApolloClient({
- ssrMode,
- cache: new InMemoryCache().restore(initialState),
+ ssrMode: typeof window !== 'undefined',
+ cache: new InMemoryCache().restore(cache),
link: createUploadLink({ uri: process.env.API_URI })
})
-export default ComposedComponent =>
+export const withData = Composed =>
class WithData extends Component {
- static displayName = `WithData(${getDisplayName(ComposedComponent)})`
-
- /**
- * Gets the initial props for a Next.js page component.
- * Executes on the server for the initial page load. Executes on the client
- * when navigating to a different route via the Link component or using the
- * routing APIs. For either environment the initial props returned must be
- * serializable to JSON.
- * @see https://github.com/zeit/next.js/#fetching-data-and-component-lifecycle
- * @param {Object} context
- * @param {String} context.pathname - Page URL path.
- * @param {String} context.asPath - Page URL path and query as shown in browser.
- * @param {Object} context.query - Query string section of the page URL parsed as an object.
- * @param {Object} context.req - HTTP request (server only).
- * @param {Object} context.res - HTTP response (server only).
- * @param {Object} context.jsonPageRes - Fetch Response (client only).
- * @param {Object} context.err - Error encountered during the rendering, if any.
- * @returns {Promise} Page component props.
- */
- static async getInitialProps(context) {
- const initialProps = {
- composedComponentProps: {
- router: {
- pathname: context.pathname,
- asPath: context.asPath,
- query: context.query
- }
- }
- }
-
- // If the page component has initial props, merge them in.
- if (ComposedComponent.getInitialProps)
- Object.assign(
- initialProps.composedComponentProps,
- await ComposedComponent.getInitialProps(context)
- )
-
- if (ssrMode) {
- const apolloClient = createApolloClient()
-
- try {
- // Recurse the component tree and prefetch all Apollo data queries to
- // populate the Apollo Client Redux store. This allows an instant
- // server side render.
- // See: https://www.apollographql.com/docs/react/recipes/server-side-rendering.html#getDataFromTree
- await getDataFromTree(
-
-
-
- )
- } catch (error) {
- // Prevent Apollo Client GraphQL errors from crashing SSR. Handle them
- // in components via the data.error prop.
- // See: https://www.apollographql.com/docs/react/basics/queries.html#graphql-query-data-error
- // eslint-disable-next-line no-console
- console.error(error.message)
- }
-
- // Forget Head items found during the getDataFromTree render to prevent
- // duplicates in the real render.
- Head.rewind()
-
- // Set Apollo Client initial state so the client can adopt data fetched
- // on the server.
- initialProps.initialState = apolloClient.cache.extract()
- }
-
- // Return the final page component initial props
- return initialProps
- }
-
constructor(props) {
super(props)
- if (ssrMode)
- // For the server an Apollo Client instance exists per request
- this.apolloClient = createApolloClient(this.props.initialState)
- else {
- // For the client an Apollo Client instance is shared between pages
- if (!apolloClient)
- apolloClient = createApolloClient(this.props.initialState)
- this.apolloClient = apolloClient
- }
+
+ // Set the ApolloClient instance used in render().
+ this.apolloClient =
+ typeof window !== 'undefined'
+ ? // Client: Shared instance, created at first render after SSR.
+ (browserApolloClient =
+ browserApolloClient || createApolloClient(props.cache))
+ : // Server: Private instance for SSR.
+ createApolloClient(props.cache)
}
+ static displayName = `WithApollo(${getDisplayName(Composed)})`
+
+ static async getInitialProps(ctx) {
+ // Use initial props from nested page decorators.
+ const props = Composed.getInitialProps
+ ? await Composed.getInitialProps(ctx)
+ : {}
+
+ // If server environment, preload the page.
+ if (ctx.req) {
+ const apolloClient = createApolloClient()
+
+ await getDataFromTree(
+
+ )
+
+ props.cache = apolloClient.cache.extract()
+ }
+
+ return props
+ }
+
+ static renderPage = ({ apolloClient, pageProps }) => (
+
+
+
+ )
+
render() {
- return (
-
-
-
- )
+ return this.constructor.renderPage({
+ apolloClient: this.apolloClient,
+ pageProps: this.props
+ })
}
}