Fetching and displaying data with GraphQL on a next.js front-end
Tags: nextjs, react, graphql, typescript
Published: 2021-03-29 10:39:29

# Setting up the front-end

In this post I will be building the frontend to the graphQL server I built in my CRUD-article and authenthication-artice. For this particular blog post we will be focusing on CRUD, so only that part is necessary.

Since I want good SEO on my front-end, so I will need SSR. To achieve this, we will use next.js with the bonus of also getting fantastic routing. I will be using [Chakra-UI](https://chakra-ui.com/) to style the app

```bash
yarn create next-app --example with-chakra-ui frontend
```

now, just `yarn dev` and you should see a nice welcome-screen. Let's delete it.😡

To convert to tsx you should:

- delete component folder
- delete any filer other than _app.js, index.js and theme.js
- rename _app.js, index.js and theme.js to _app.tsx, index.tsx and theme.tsx
- write this in your index.tsx

```tsx
import { Box } from "@chakra-ui/react"
import React from "react"

const Index = () => (
  <Box>hello</Box>
)

export default Index
```

leaving you with a project structure similar to:

![Project structure](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sb9hm717dpbgk1v9f409.png)

Make sure to add the typescript types if you haven't already.

```bash
yarn add --dev typescript @types/node
```

Finally, time to develop. To begin with, I want to load a list of the basketball-games we have in our backend!

We will need the [Apollo Client](https://www.apollographql.com/docs/react/) to manage the state, fetch, cache and (later) modify the application data. The apollo client has many different features, and I will cover more in the future!

## Apollo-client

add the apollo-client and Graphql

```bash
yarn add @apollo/client graphql
```

We need to configure Apollo Client in `_app.tsx`

```tsx
import { ChakraProvider, ColorModeProvider } from '@chakra-ui/react'

import theme from '../theme'
import React from 'react';
import ReactDOM from 'react-dom';
import './styles/index.css';
import {
  ApolloProvider,
  ApolloClient,
  createHttpLink,
  InMemoryCache
} from '@apollo/client';

function MyApp({ Component, pageProps }) {

const httpLink = createHttpLink({
  uri: 'http://localhost:4000/graphql'
});

const client = new ApolloClient({
  link: httpLink,
  cache: new InMemoryCache()
});

  return (
    <ApolloProvider client ={client}>
	   <ChakraProvider resetCSS theme={theme}>
      <ColorModeProvider
        options={{
          useSystemColorMode: true,
        }}
      >
        <Component {...pageProps} />
      </ColorModeProvider>
    </ChakraProvider>
    </ApolloProvider>
  )
}

export default MyApp
```

First we create a `httplink` pointing to our [localhost](http://localhost). We need to pass the link to a new instance of the `ApolloClient()`. We also create a new instance of `InMemoryCache` which is the cache used by Apollo. 

Lastly, make sure to wrap your app in `<ApolloProvider>` and pass in the client you created in the few lines above. 

If you are getting a CORS-error, add these lines in `index.ts`

```tsx
app.use(
    cors({
      origin: "http://localhost:3000",
      credentials: true
    }),
```

It baically tells CORS that requests from the front-end, [http://localhost:3000](http://localhost:3000), are safe to receive.

To make our lives easier, we will be using an amazing tool called GraphQL code-gen.

## GraphQL Code-Gen

Let's add [graphQL code-gen](https://www.graphql-code-generator.com/) to our project! GraphQL code generator is a tool to generate types and hooks for your graphQL mutations and queries. For example, code-gen would generate hooks for the createGame mutation we created in the previous tutorial, so we can use it on the front-end.

We need to go through a little setup, I promise it will be worth it🙏

Install the CLI and typescript types on the front-end:

```bash
yarn add -D @graphql-codegen/cli
yarn add @graphql-codegen/typescript-operations
```

We need to initialize graphQL codegen. When initializing, you will be asked some questions about your project. You can copy mine if you want. The questions help the program create the config file, `codegen.yaml`, which you can always edit later.

```bash
yarn graphql-codegen init
```

Here are my **answers:**

- default
- http://localhost:4000/graphql
- src/graphql/**/*.graphql
- default
- default
- no
- "gen"

Now we need to create some folders

1. Create a folder called "generated" under the "src"-folder. Here all of the code generated by graphQL code-gen will be saved. 
2. Create a new folder called "graphql" and inside of that create a folder called "queries". We now have a folder where we can write our queries to interact with the backend.

You should have a project structure similiar to:

```bash
├── generated
│   └── 
├── graphql
│   └── queries
│				└── 
├── pages
│   ├── _app.tsx
│   └── index.tsx
├── package-lock.json
├── package.json
├── codegen.yml
├── next-env.d.ts
├── tsconfig.json
```

## Fetching and displaying the data

First, create `query.graphql` file:

```graphql
query Games {
  games {
    id
    myTeamScore
    opponentTeamScore
    date
  }
}
```

This is simply the same query which you would write in the graphQL playground. It gets an array of `Game`-objects. I have named the query "Games". If you are using VS-Code, I can recommend this [plugin](https://marketplace.visualstudio.com/items?itemName=kumar-harsh.graphql-for-vscode) to get syntax-highlighting in .graphql files

Now we can just run

```bash
yarn gen
```

in the terminal. This will generate the required hooks for all of our `.graphql`-files and tbeir corresponding types. 

Navigate over to `index.tsx`, where we will map over the data.

```tsx
const Index = () => {
  const { data } = useGamesQuery();

  return (
    <Box>
      {!data
        ? null
        : data.games.map((e) => {
            return <Box key={e.id}>{e.date}</Box>;
          })}
      :
    </Box>
  );
};
```

I map over the array of `Game`s gotten from `gamesQuery()`, and show the `date` of each game!

Take a minute to appreciate how easy that was🙏 🙏 

**The workflow is:**

- Write your query/mutation in the graphQL playground
- Paste into a `.graphQL` file inside either the "query"- or "mutation"-folder
- run `yarn gen`
- We now have fully typed hooks to do whatever we want.

Seriously, just look at this autofill❤️ Just pick the fields that you want to display 🤯

![Example of autofill](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yo8iojujw7o5r9smu90h.gif)

If the user is on a slow-connection, we should show a loading-animation to indicate that the data is on it's way.

### Loading

By hovering over `useGamesQuery()`, code-gen has already written the documentation for us😅

![useGamesQuery details](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7pknil8au8w4s2z57fmj.png)

As you can see, we can also get a `loading` boolean, which can be used to show a spinner if a user has a slow connection. Let's develop that feature!

```tsx
if (loading) {
    return <Spinner></Spinner>;
  } else {
	//display the data here
}
```

So if the data is loading, show a spinner. I usually use the spinner from Chakra-UI, it's pretty great.

## Styling

While you were reading the article, I styled the app😆 Chakra-UI makes it pretty easy, as we get a ton of pretty components out the box. In general, I am also a fan of CSS-in-JS, which Chakra also supports.

I can make a new React component, `GameCard.tsx`. Here is the code for the styling. 

```tsx
interface GameCardProps {
  date: string;
  myTeamScore: number;
  opponentTeamScore: number;
}

export const GameCard: React.FC<GameCardProps> = (props) => {
  return (
    <Box maxW="xs" m={2} borderWidth="1px" borderRadius="lg" overflow="hidden">
      <Box p="6">
        <Box d="flex" alignItems="baseline">
          {props.myTeamScore > props.opponentTeamScore ? (
            <Badge borderRadius="full" px="2" colorScheme="teal">
              Win
            </Badge>
          ) : (
            <Badge borderRadius="full" px="2" colorScheme="red">
              Loss
            </Badge>
          )}
          <Box
            color="gray.500"
            fontWeight="semibold"
            letterSpacing="wide"
            fontSize="xs"
            textTransform="uppercase"
            ml="2"
          >
            {props.date}
          </Box>
        </Box>

        <Box
          mt="1"
          maxW="50%"
          fontWeight="semibold"
          as="h4"
          lineHeight="tight"
          isTruncated
        >
          <Flex ml="auto">
            <Text>{props.myTeamScore}-</Text>
            <Text>{props.opponentTeamScore}</Text>
          </Flex>
        </Box>
      </Box>
    </Box>
  );
};
```

Since this isn't a guide on styling, I won't go through everything🙂

We can now map over our new `<GameCards>` in `index.tsx` and just pass in the data via props.

```tsx
<Box>
        {!data
          ? null
          : data.games.map((e) => {
              return (
                <GameCard
                  myTeamScore={e.myTeamScore}
                  opponentTeamScore={e.opponentTeamScore}
                  date={e.date}
                  key={e.id}
                ></GameCard>
              );
            })}
</Box>
```

The resulting cards will look like this:

![Styled cards](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yptd6vi1rlbjxkhcmeku.png)

While we are fetching the data perfectly, our database clearly consists of false, incorrect data, since we are not winning all the time. jk.

## Conclusion

Nice! We have now learnt how to show the data in our database fetched with GraphQL. As you have noticed, GraphQL Code Gen simplifies our lives considerably🥰