diff --git a/examples/api-routes-apollo-server-and-client/apollo/client.js b/examples/api-routes-apollo-server-and-client/apollo/client.js
index 26ae378500bdc..dd890d1d3ffdf 100644
--- a/examples/api-routes-apollo-server-and-client/apollo/client.js
+++ b/examples/api-routes-apollo-server-and-client/apollo/client.js
@@ -30,7 +30,7 @@ export function initializeApollo(initialState = null) {
const _apolloClient = apolloClient ?? createApolloClient()
// If your page has Next.js data fetching methods that use Apollo Client, the initial state
- // get hydrated here
+ // gets hydrated here
if (initialState) {
_apolloClient.cache.restore(initialState)
}
diff --git a/examples/with-apollo/lib/apolloClient.js b/examples/with-apollo/lib/apolloClient.js
index 77ee7a59b1149..18c52651590cd 100644
--- a/examples/with-apollo/lib/apolloClient.js
+++ b/examples/with-apollo/lib/apolloClient.js
@@ -20,7 +20,7 @@ export function initializeApollo(initialState = null) {
const _apolloClient = apolloClient ?? createApolloClient()
// If your page has Next.js data fetching methods that use Apollo Client, the initial state
- // get hydrated here
+ // gets hydrated here
if (initialState) {
_apolloClient.cache.restore(initialState)
}
diff --git a/examples/with-graphql-hooks/README.md b/examples/with-graphql-hooks/README.md
index ae120414a1446..e4aef1b537daf 100644
--- a/examples/with-graphql-hooks/README.md
+++ b/examples/with-graphql-hooks/README.md
@@ -12,8 +12,6 @@ Deploy the example using [Vercel](https://vercel.com):
[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/import/project?template=https://github.com/vercel/next.js/tree/canary/examples/with-graphql-hooks)
-_Live Example: https://next-with-graphql-hooks.now.sh_
-
## How to use
### Using `create-next-app`
diff --git a/examples/with-graphql-hooks/components/header.js b/examples/with-graphql-hooks/components/header.js
index 44be0c39b5abd..f789f939acd56 100644
--- a/examples/with-graphql-hooks/components/header.js
+++ b/examples/with-graphql-hooks/components/header.js
@@ -1,28 +1,30 @@
import Link from 'next/link'
-import { withRouter } from 'next/router'
+import { useRouter } from 'next/router'
-const Header = ({ router: { pathname } }) => (
-
-)
+export default function Header() {
+ const { pathname } = useRouter()
-export default withRouter(Header)
+ return (
+
+ )
+}
diff --git a/examples/with-graphql-hooks/components/post-list.js b/examples/with-graphql-hooks/components/post-list.js
index fce9e43e2f185..45707ece6fec2 100644
--- a/examples/with-graphql-hooks/components/post-list.js
+++ b/examples/with-graphql-hooks/components/post-list.js
@@ -1,4 +1,4 @@
-import React, { Fragment, useState } from 'react'
+import { useState } from 'react'
import { useQuery } from 'graphql-hooks'
import ErrorMessage from './error-message'
import PostUpvoter from './post-upvoter'
@@ -19,17 +19,22 @@ export const allPostsQuery = `
}
`
+export const allPostsQueryOptions = (skip = 0) => ({
+ variables: { skip, first: 10 },
+ updateData: (prevResult, result) => ({
+ ...result,
+ allPosts: prevResult
+ ? [...prevResult.allPosts, ...result.allPosts]
+ : result.allPosts,
+ }),
+})
+
export default function PostList() {
const [skip, setSkip] = useState(0)
- const { loading, error, data, refetch } = useQuery(allPostsQuery, {
- variables: { skip, first: 10 },
- updateData: (prevResult, result) => ({
- ...result,
- allPosts: prevResult
- ? [...prevResult.allPosts, ...result.allPosts]
- : result.allPosts,
- }),
- })
+ const { loading, error, data, refetch } = useQuery(
+ allPostsQuery,
+ allPostsQueryOptions(skip)
+ )
if (error) return
if (!data) return
Loading
@@ -38,7 +43,7 @@ export default function PostList() {
const areMorePosts = allPosts.length < _allPostsMeta.count
return (
-
+ <>
{
refetch({ variables: { skip: 0, first: allPosts.length } })
@@ -109,6 +114,6 @@ export default function PostList() {
}
`}
-
+ >
)
}
diff --git a/examples/with-graphql-hooks/lib/graphql-client.js b/examples/with-graphql-hooks/lib/graphql-client.js
new file mode 100644
index 0000000000000..e7d8ad8258495
--- /dev/null
+++ b/examples/with-graphql-hooks/lib/graphql-client.js
@@ -0,0 +1,40 @@
+import { useMemo } from 'react'
+import { GraphQLClient } from 'graphql-hooks'
+import memCache from 'graphql-hooks-memcache'
+
+let graphQLClient
+
+function createClient(initialState) {
+ return new GraphQLClient({
+ ssrMode: typeof window === 'undefined',
+ url: 'https://api.graph.cool/simple/v1/cixmkt2ul01q00122mksg82pn', // Server URL (must be absolute)
+ cache: memCache({ initialState }),
+ })
+}
+
+export function initializeGraphQL(initialState = null) {
+ const _graphQLClient = graphQLClient ?? createClient(initialState)
+
+ // After navigating to a page with an initial GraphQL state, create a new cache with the
+ // current state merged with the incoming state and set it to the GraphQL client.
+ // This is necessary because the initial state of `memCache` can only be set once
+ if (initialState && graphQLClient) {
+ graphQLClient.cache = memCache({
+ initialState: Object.assign(
+ graphQLClient.cache.getInitialState(),
+ initialState
+ ),
+ })
+ }
+ // For SSG and SSR always create a new GraphQL Client
+ if (typeof window === 'undefined') return _graphQLClient
+ // Create the GraphQL Client once in the client
+ if (!graphQLClient) graphQLClient = _graphQLClient
+
+ return _graphQLClient
+}
+
+export function useGraphQLClient(initialState) {
+ const store = useMemo(() => initializeGraphQL(initialState), [initialState])
+ return store
+}
diff --git a/examples/with-graphql-hooks/lib/graphql-request.js b/examples/with-graphql-hooks/lib/graphql-request.js
new file mode 100644
index 0000000000000..130da12c15231
--- /dev/null
+++ b/examples/with-graphql-hooks/lib/graphql-request.js
@@ -0,0 +1,30 @@
+const defaultOpts = { useCache: true }
+/**
+ * Returns the result of a GraphQL query. It also adds the result to the
+ * cache of the GraphQL client for better initial data population in pages.
+ *
+ * Note: This helper tries to imitate what the query hooks of `graphql-hooks`
+ * do internally to make sure we generate the same cache key
+ */
+export default async function graphQLRequest(client, query, options) {
+ const opts = { ...defaultOpts, ...options }
+ const operation = {
+ query,
+ variables: opts.variables,
+ operationName: opts.operationName,
+ persisted: opts.persisted,
+ }
+
+ if (opts.persisted || (client.useGETForQueries && !opts.isMutation)) {
+ opts.fetchOptionsOverrides = {
+ ...opts.fetchOptionsOverrides,
+ method: 'GET',
+ }
+ }
+
+ const cacheKey = client.getCacheKey(operation, opts)
+ const cacheValue = await client.request(operation, opts)
+
+ client.saveCache(cacheKey, cacheValue)
+ return cacheValue
+}
diff --git a/examples/with-graphql-hooks/lib/init-graphql.js b/examples/with-graphql-hooks/lib/init-graphql.js
deleted file mode 100644
index 09492dac49202..0000000000000
--- a/examples/with-graphql-hooks/lib/init-graphql.js
+++ /dev/null
@@ -1,27 +0,0 @@
-import { GraphQLClient } from 'graphql-hooks'
-import memCache from 'graphql-hooks-memcache'
-
-let graphQLClient = null
-
-function create(initialState = {}) {
- return new GraphQLClient({
- ssrMode: typeof window === 'undefined',
- url: 'https://api.graph.cool/simple/v1/cixmkt2ul01q00122mksg82pn',
- cache: memCache({ initialState }),
- })
-}
-
-export default function initGraphQL(initialState) {
- // Make sure to create a new client for every server-side request so that data
- // isn't shared between connections (which would be bad)
- if (typeof window === 'undefined') {
- return create(initialState)
- }
-
- // Reuse client on the client-side
- if (!graphQLClient) {
- graphQLClient = create(initialState)
- }
-
- return graphQLClient
-}
diff --git a/examples/with-graphql-hooks/lib/with-graphql-client.js b/examples/with-graphql-hooks/lib/with-graphql-client.js
deleted file mode 100644
index 4f46c79c9bd66..0000000000000
--- a/examples/with-graphql-hooks/lib/with-graphql-client.js
+++ /dev/null
@@ -1,60 +0,0 @@
-import React from 'react'
-import initGraphQL from './init-graphql'
-import Head from 'next/head'
-import { getInitialState } from 'graphql-hooks-ssr'
-
-export default function withGraphqlClient(App) {
- return class GraphQLHooks extends React.Component {
- static displayName = 'GraphQLHooks(App)'
- static async getInitialProps(ctx) {
- const { AppTree } = ctx
-
- let appProps = {}
- if (App.getInitialProps) {
- appProps = await App.getInitialProps(ctx)
- }
-
- // Run all GraphQL queries in the component tree
- // and extract the resulting data
- let graphQLState = {}
- if (typeof window === 'undefined') {
- const graphQLClient = initGraphQL()
- try {
- // Run all GraphQL queries
- graphQLState = await getInitialState({
- App: ,
- client: graphQLClient,
- })
- } catch (error) {
- // Prevent GraphQL hooks client errors from crashing SSR.
- // Handle them in components via the state.error prop:
- // https://github.com/nearform/graphql-hooks#usequery
- console.error('Error while running `getInitialState`', error)
- }
-
- // getInitialState does not call componentWillUnmount
- // head side effect therefore need to be cleared manually
- Head.rewind()
- }
-
- return {
- ...appProps,
- graphQLState,
- }
- }
-
- constructor(props) {
- super(props)
- if (props.graphQLClient) {
- // During SSR the GraphQL client is provided as a prop
- this.graphQLClient = props.graphQLClient
- } else {
- this.graphQLClient = initGraphQL(props.graphQLState)
- }
- }
-
- render() {
- return
- }
- }
-}
diff --git a/examples/with-graphql-hooks/package.json b/examples/with-graphql-hooks/package.json
index a0007dd1f25b8..5ddbcccd06efb 100644
--- a/examples/with-graphql-hooks/package.json
+++ b/examples/with-graphql-hooks/package.json
@@ -1,25 +1,18 @@
{
"name": "with-graphql-hooks",
"version": "1.0.0",
- "description": "",
- "main": "index.js",
"scripts": {
"dev": "next",
"build": "next build",
"start": "next start"
},
- "author": "",
"license": "ISC",
"dependencies": {
"graphql-hooks": "^4.4.4",
"graphql-hooks-memcache": "^1.3.2",
- "graphql-hooks-ssr": "^1.1.5",
"next": "latest",
"prop-types": "^15.7.2",
"react": "^16.8.2",
"react-dom": "^16.8.2"
- },
- "browser": {
- "graphql-hooks-ssr": false
}
}
diff --git a/examples/with-graphql-hooks/pages/_app.js b/examples/with-graphql-hooks/pages/_app.js
index 446621c17319d..9420b692f11ee 100644
--- a/examples/with-graphql-hooks/pages/_app.js
+++ b/examples/with-graphql-hooks/pages/_app.js
@@ -1,16 +1,12 @@
-import App from 'next/app'
-import withGraphQLClient from '../lib/with-graphql-client'
import { ClientContext } from 'graphql-hooks'
+import { useGraphQLClient } from '../lib/graphql-client'
-class MyApp extends App {
- render() {
- const { Component, pageProps, graphQLClient } = this.props
- return (
-
-
-
- )
- }
-}
+export default function App({ Component, pageProps }) {
+ const graphQLClient = useGraphQLClient(pageProps.initialGraphQLState)
-export default withGraphQLClient(MyApp)
+ return (
+
+
+
+ )
+}
diff --git a/examples/with-graphql-hooks/pages/index.js b/examples/with-graphql-hooks/pages/index.js
index bb92144340dce..0f7cd40deaa80 100644
--- a/examples/with-graphql-hooks/pages/index.js
+++ b/examples/with-graphql-hooks/pages/index.js
@@ -1,6 +1,11 @@
+import { initializeGraphQL } from '../lib/graphql-client'
+import graphQLRequest from '../lib/graphql-request'
import App from '../components/app'
import Header from '../components/header'
-import PostList from '../components/post-list'
+import PostList, {
+ allPostsQuery,
+ allPostsQueryOptions,
+} from '../components/post-list'
export default function Home() {
return (
@@ -10,3 +15,16 @@ export default function Home() {
)
}
+
+export async function getStaticProps() {
+ const client = initializeGraphQL()
+
+ await graphQLRequest(client, allPostsQuery, allPostsQueryOptions())
+
+ return {
+ props: {
+ initialGraphQLState: client.cache.getInitialState(),
+ },
+ unstable_revalidate: 1,
+ }
+}