How to use NextJS with Apollo
October 26, 2020
💈
Maybe you found yourself in the same situation as I did. You’re building a NextJS app with a NodeJS + Apollo GraphQL backend.
Because you’re using NextJS, you probably want some of your pages to be static or server-side rendered.
Now, as you’re finding out about how to fetch from your graphQL data in this unmissable tutorial, you realize that the UseQuery
hook could be quite useful.
Fetching data with the useQuery
hook
Here’s the example that’s given to us in the referenced Apollo GraphQL tutorial :
import { gql, useQuery } from "@apollo/client"
const GET_DOGS = gql`
query GetDogs {
dogs {
id
breed
}
}
`
function Dogs({ onDogSelected }) {
const { loading, error, data } = useQuery(GET_DOGS)
if (loading) return "Loading..."
if (error) return `Error! ${error.message}`
return (
<select name="dog" onChange={onDogSelected}>
{data.dogs.map(dog => (
<option key={dog.id} value={dog.breed}>
{dog.breed}
</option>
))}
</select>
)
}
The useQuery
hook is super useful ! We just pass it the graphQL query and it handles the loading
and error
states.
This is a perfectly standart React
component, but how would you do this if you were generating the page at build time (static pages) or on a server (server-side pages)?
Build static pages : don’t forget the Rules of Hooks
When hooks got released in React 16.8, Facebook added a very important piece of document to their docs : Rules of Hooks. One of those rules is “Only Call Hooks from React Functions. Don’t call Hooks from regular JavaScript functions.”.
This is quite interesting in our case. Indeed, the useQuery
hook is perfectly acceptable for client-side rendered pages, but if we’re building a static page, the query isn’t executed inside the component.
getStaticPaths and getStaticProps
To create static pages in NextJS, you first have to create the paths
. To do so, we create a getStaticPaths
function. You’ll probably want to get the paths from your graphQL API, but because we can’t call the useQuery
hook (we’re not inside a component), we’ll be using graphql-request
, a minimal GraphQL client.
We’ll be getting the data directly with a simple request
.
Let’s say we’re building a [movieName].jsx
page. Here’s what the getStaticPaths
and getStaticProps
functions will look like.
import { request, gql } from "graphql-request"
const nameQuery = gql`
query getMovieNames{
movies {
name
}
}
`
const fullQuery = gql`
query getMovie($name: String!){
movie(name: $name){
id
name
year
actors {
firstname
lastname
}
}
}
`
export const getStaticPaths = async () => {
const res = await request("https://supercoolapi.cool/v1/movies", nameQuery)
// Get the paths we want to pre-render based on users
const paths = res.movies.map(movie) => ({
params: { movieName: movie.name },
}))
// We'll pre-render only these paths at build time.
// { fallback: false } means other routes should 404.
return { paths, fallback: false }
}
export const getStaticProps = async ({ params }) => {
try {
const name = params?.movieName
const res = await request("https://supercoolapi.cool/v1/movies", fullQuery, { name: name })
// By returning { props: producer }, the StaticPropsDetail component
// will receive `producer` as a prop at build time
return { props: { movie: res.movie } }
} catch (err) {
return { props: { errors: err.message } }
}
}
Conclusion
Time to sum it up !
Here’s how you should fetch your data from your Apollo GraphQL API :
- For a standard component (client side rendered page) : go with the
useQuery
hook - For a static page : use a minimal graphQL client such as
graphql-request
and make a simple request ingetStaticPaths
andgetStaticProps
. - For a server-side rendered page : I’ll update this article pretty soon with a new section covering this problematic!
See ya 𓁚