Skip to content

Commit

Permalink
[Examples] Move with-apollo to SSG (vercel#13742)
Browse files Browse the repository at this point in the history
Based on vercel#13607 - I created a new PR as I can't push changes to the initial PR.

Migrated the Apollo client to use SSG, also removed the link to the live demo because I don't know who the owner is or how to update the deployment.

The implementation is pretty simple and will be added to all the other Apollo examples
  • Loading branch information
lfades authored and rokinsky committed Jul 11, 2020
1 parent bd13f43 commit bb298cc
Show file tree
Hide file tree
Showing 11 changed files with 133 additions and 276 deletions.
13 changes: 5 additions & 8 deletions examples/with-apollo/README.md
Original file line number Diff line number Diff line change
@@ -1,24 +1,21 @@
# Apollo Example

[Apollo](https://www.apollographql.com/client/) is a GraphQL client that allows you to easily query the exact data you need from a GraphQL server. In addition to fetching and mutating data, Apollo analyzes your queries and their results to construct a client-side cache of your data, which is kept up to date as further queries and mutations are run, fetching more results from the server.
[Apollo](https://www.apollographql.com/client/) is a GraphQL client that allows you to easily query the exact data you need from a GraphQL server. In addition to fetching and mutating data, Apollo analyzes your queries and their results to construct a client-side cache of your data, which is kept up to date as further queries and mutations are run.

In this simple example, we integrate Apollo seamlessly with Next by wrapping our `pages/index.js` inside a [higher-order component (HOC)](https://facebook.github.io/react/docs/higher-order-components.html). Using the HOC pattern we're able to pass down a central store of query result data created by Apollo into our React component hierarchy defined inside each page of our Next application.

On initial page load, while on the server and inside `getInitialProps`, we invoke the Apollo method, [`getDataFromTree`](https://www.apollographql.com/docs/react/api/react-ssr/#getdatafromtree). This method returns a promise; at the point in which the promise resolves, our Apollo Client store is completely initialized.
In this simple example, we integrate Apollo seamlessly with [Next.js data fetching methods](https://nextjs.org/docs/basic-features/data-fetching) to fetch queries in the server and hydrate them in the browser.

This example relies on [graph.cool](https://www.graph.cool) for its GraphQL backend.

Note: Do not be alarmed that you see two renders being executed. Apollo recursively traverses the React render tree looking for Apollo query components. When it has done that, it fetches all these queries and then passes the result to a cache. This cache is then used to render the data on the server side (another React render).
https://www.apollographql.com/docs/react/api/react-ssr/#getdatafromtree
## Demo

[https://next-with-apollo.now.sh](https://next-with-apollo.now.sh)

## Deploy your own

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-apollo)

_Live Example: https://next-with-apollo.now.sh_

## How to use

### Using `create-next-app`
Expand Down
16 changes: 0 additions & 16 deletions examples/with-apollo/apolloClient.js

This file was deleted.

62 changes: 32 additions & 30 deletions examples/with-apollo/components/Header.js
Original file line number Diff line number Diff line change
@@ -1,33 +1,35 @@
import { useRouter } from 'next/router'
import Link from 'next/link'
import { withRouter } from 'next/router'

const Header = ({ router: { pathname } }) => (
<header>
<Link href="/">
<a className={pathname === '/' ? 'is-active' : ''}>Home</a>
</Link>
<Link href="/client-only">
<a className={pathname === '/client-only' ? 'is-active' : ''}>
Client-Only
</a>
</Link>
<Link href="/about">
<a className={pathname === '/about' ? 'is-active' : ''}>About</a>
</Link>
<style jsx>{`
header {
margin-bottom: 25px;
}
a {
font-size: 14px;
margin-right: 15px;
text-decoration: none;
}
.is-active {
text-decoration: underline;
}
`}</style>
</header>
)
export default function Header() {
const { pathname } = useRouter()

export default withRouter(Header)
return (
<header>
<Link href="/">
<a className={pathname === '/' ? 'is-active' : ''}>Home</a>
</Link>
<Link href="/about">
<a className={pathname === '/about' ? 'is-active' : ''}>About</a>
</Link>
<Link href="/client-only">
<a className={pathname === '/client-only' ? 'is-active' : ''}>
Client-Only
</a>
</Link>
<style jsx>{`
header {
margin-bottom: 25px;
}
a {
font-size: 14px;
margin-right: 15px;
text-decoration: none;
}
.is-active {
text-decoration: underline;
}
`}</style>
</header>
)
}
1 change: 1 addition & 0 deletions examples/with-apollo/components/PostList.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export const ALL_POSTS_QUERY = gql`
}
}
`

export const allPostsQueryVars = {
skip: 0,
first: 10,
Expand Down
175 changes: 0 additions & 175 deletions examples/with-apollo/lib/apollo.js

This file was deleted.

38 changes: 38 additions & 0 deletions examples/with-apollo/lib/apolloClient.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { useMemo } from 'react'
import { ApolloClient } from 'apollo-client'
import { InMemoryCache } from 'apollo-cache-inmemory'
import { HttpLink } from 'apollo-link-http'

let apolloClient

function createApolloClient() {
return new ApolloClient({
ssrMode: typeof window === 'undefined',
link: new HttpLink({
uri: 'https://api.graph.cool/simple/v1/cixmkt2ul01q00122mksg82pn', // Server URL (must be absolute)
credentials: 'same-origin', // Additional fetch() options like `credentials` or `headers`
}),
cache: new InMemoryCache(),
})
}

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
if (initialState) {
_apolloClient.cache.restore(initialState)
}
// For SSG and SSR always create a new Apollo Client
if (typeof window === 'undefined') return _apolloClient
// Create the Apollo Client once in the client
if (!apolloClient) apolloClient = _apolloClient

return _apolloClient
}

export function useApollo(initialState) {
const store = useMemo(() => initializeApollo(initialState), [initialState])
return store
}
7 changes: 3 additions & 4 deletions examples/with-apollo/package.json
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
{
"name": "with-apollo",
"version": "2.0.0",
"version": "1.0.0",
"scripts": {
"dev": "next",
"build": "next build",
"start": "next start"
},
"dependencies": {
"@apollo/react-hooks": "3.1.3",
"@apollo/react-ssr": "3.1.3",
"apollo-cache-inmemory": "1.6.5",
"apollo-client": "2.6.8",
"apollo-link-http": "1.5.16",
Expand All @@ -19,8 +18,8 @@
"react": "^16.7.0",
"react-dom": "^16.7.0"
},
"license": "ISC",
"devDependencies": {
"babel-plugin-graphql-tag": "^2.5.0"
}
},
"license": "ISC"
}
12 changes: 12 additions & 0 deletions examples/with-apollo/pages/_app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { ApolloProvider } from '@apollo/react-hooks'
import { useApollo } from '../lib/apolloClient'

export default function App({ Component, pageProps }) {
const apolloClient = useApollo(pageProps.initialApolloState)

return (
<ApolloProvider client={apolloClient}>
<Component {...pageProps} />
</ApolloProvider>
)
}
Loading

0 comments on commit bb298cc

Please sign in to comment.