next-with-apollo
Apollo HOC for Next.js
How to use
Install the package with npm
npm install next-with-apollo
or with yarn
yarn add next-with-apollo
Create the HOC using a basic setup
import withApollo from 'next-with-apollo'
import { InMemoryCache } from 'apollo-cache-inmemory'
import { HttpLink } from 'apollo-link-http'
import { GRAPHQL_URL } from '../configs'
export default withApollo({
client: () => ({
cache: new InMemoryCache()
}),
link: {
http: ({ headers }) => new HttpLink({
uri: GRAPHQL_URL,
credentials: 'same-origin',
headers
})
}
})
Wrap your Next page
import withApollo from '../lib/withApollo'
export default withApollo(props => (
<h1>Hello World!</1>
))
Apollo-boost
You can also use apollo-boost instead
import withApollo from 'next-with-apollo'
import ApolloClient from 'apollo-boost'
import { GRAPHQL_URL } from '../configs'
export default withApolloHOC({
client: new ApolloClient({ uri: GRAPHQL_URL })
})
How it works
next-with-apollo
will create a Higher-Order Component (HOC) with your configuration that can be used to wrap an Apollo client
to any Next
page, it will also fetch your queries before the first page load to hydrate the store on SSR
Advanced Usage
Below is a config using every possible option accepted by the package, very similar to my own config in an app with a lot of Apollo features
import withApollo from 'next-with-apollo'
import { InMemoryCache } from 'apollo-cache-inmemory'
import { WebSocketLink } from 'apollo-link-ws'
import { HttpLink } from 'apollo-link-http'
import auth from '../auth'
import { GRAPHQL_URL, WS_URL } from '../configs'
export default withApollo({
getInitialProps: false,
link: {
http: ({ headers }) => {
if (!process.browser && headers) {
headers.ssr = '1'
}
return new HttpLink({
uri: GRAPHQL_URL,
credentials: 'same-origin',
headers
})
},
setContext: async ({ headers }) => ({
headers: {
...headers,
authorization: await auth.getAccessToken()
}
}),
ws: () =>
new WebSocketLink({
uri: WS_URL,
options: {
reconnect: true,
connectionParams: {
authorization: auth.getAccessToken()
}
}
}),
onError: ({ graphQLErrors, networkError }) => {
if (graphQLErrors) {
graphQLErrors.map(err =>
console.log(`[GraphQL error]: Message: ${err.message}`)
)
}
if (networkError) console.log(`[Network error]: ${networkError}`)
}
},
client: ({ headers, link }) => ({
cache: new InMemoryCache({
dataIdFromObject: ({ id, __typename }) =>
id && __typename ? __typename + id : null
})
})
})
You can also use a static prop that comes with the HOC to get the initial apollo props, specially useful when you have multiple HOCs for a page but you just don't want to be cloning statics all the time, here's an example
import withApollo from './withApollo'
const withInitialProps = ({ getInitialProps }) => Child => {
Child.getInitialProps = async ctx => {
const props = {
...(await withApp.getInitialProps(ctx)),
...(await withAuth.getInitialProps(ctx)),
...(getInitialProps ? await getInitialProps(ctx) : {})
}
Object.assign(props, await withApollo.getInitialProps(Child)(ctx, props))
return props
}
return Child
}
export default Child =>
compose(
withInitialProps(Child),
withSentry,
withAuth,
withApollo,
withRedux(getReducer(Child)),
withAppLayout(Child.layout),
withApp
)(Child)
In the above example you will not need to care at all about the HOCs cloning statics and it just looks very clean