NextJS has made server-side rendering cool and easy. It's almost irresistible not using it, as it comes with so many things out of the box.
In this post, we will be fetching remote data in a new NextJS App using a GraphQL API. We'll be using useSWR and graphql-request. We'll use Chakra UI to beautify our app and https://github.com/lennertVanSever/graphcountries for data source.
*Step 1: * Create a new app with next-app
yarn create next-app
# or
npm init next-app
Follow the prompt and choose Default starter app
Step 2: Install useSWR
and graphql-request
for data fetching
cd into the directory and install the dependencies
yarn add graphql-request swr
# or
npm install graphql-request swr
*Step 3: * Install Chakra UI(This step is optional, but Chakra UI is awesome)
yarn add @chakra-ui/core @emotion/core @emotion/styled emotion-theming
# or
npm install @chakra-ui/core @emotion/core @emotion/styled emotion-theming
Then, open the folder in your favourite editor
Step 4: Create a theme file, extending the default theme from Chakra UI
components/theme.js
import { theme } from "@chakra-ui/core";
const customTheme = {
...theme,
breakpoints: ["30em", "48em", "62em", "80em"],
fonts: {
heading: '"Avenir Next", sans-serif',
body: "system-ui, sans-serif",
mono: "Menlo, monospace",
},
fontSizes: {
xs: "0.75rem",
sm: "0.875rem",
md: "1rem",
lg: "1.125rem",
xl: "1.25rem",
"2xl": "1.5rem",
"3xl": "1.875rem",
"4xl": "2.25rem",
"5xl": "3rem",
"6xl": "4rem",
},
colors: {
...theme.colors,
brand: {
900: "#1a365d",
800: "#153e75",
700: "#2a69ac",
},
},
};
export default customTheme;
NextJS uses file-based routing. So, every file in pages
directory become a route, by default.
So, if we had theme.js
in the pages
directory, we would end up with a /theme
route.
Hence, non-route files are to be placed in other directories outside of pages
Step 5: Create a layout file to inject the theme at the root of our application
components/layout.js
import { ThemeProvider, CSSReset } from "@chakra-ui/core";
import theme from "./theme";
export default ({ children }) => (
<ThemeProvider theme={theme}>
<CSSReset />
{children}
</ThemeProvider>
);
Step 6: Create a barebones homepage with static content
pages/index.js
import Head from "next/head";
import { Heading } from "@chakra-ui/core";
import Layout from "..components/layout";
export default function Home() {
return (
<>
<Head>
<title>Countries</title>
</Head>
<Layout>
<Heading size="2xl" as="center">
Countries
</Heading>
</Layout>
</>
);
}
Step 7: Import graphql-request and swr for data fetching
The pages/index.js
import section should, then, look like this:
import Head from "next/head";
import { Heading, Grid, Box, Badge, Image } from "@chakra-ui/core";
import { request } from "graphql-request";
import useSWR from "swr";
import Layout from "../components/layout";
Step 8: Initialise the query and API endpoint:
pages/index.js
const API_ENDPOINT = 'https://api.graph.cool/simple/v1/movies'
const countriesQuery = `{
Country{
_id
name
capital
populationDensity
currencies {
_id
code
}
timezones {
_id
name
}
officialLanguages {
_id
name
}
flag {
_id
svgFile
}
}
}`
You can put your API endpoint in a .env file and you, probably, should. Link here: https://nextjs.org/docs/basic-features/environment-variables
Step 9: Make a request to the endpoint using SWR
Within the Home
function before the return
block:
const { data: countries, error } = useSWR(countriesQuery, (query) =>
request(API_ENDPOINT, query)
);
useSWR
returns 2 values: data and error, based on the status of the request.
If you console.log({ countries, error });
at this point, you should see your data or error
**Step 10: **Prepare the component that will display the result
components/country.js
import { Box, Badge, Image } from "@chakra-ui/core";
const Country = ({ country }) => (
<Box maxW="sm" borderWidth="1px" rounded="lg" overflow="hidden">
<Image src={country.flag?.svgFile} alt={country.nativeName} />
<Box p="6">
<Box d="flex" alignItems="baseline">
{country.currencies &&
country.currencies.map((currency) => (
<Badge rounded="full" px="2" variantColor="teal" key={currency._id}>
{currency.name}
</Badge>
))}
<Box
color="gray.500"
fontWeight="semibold"
letterSpacing="wide"
fontSize="xs"
textTransform="uppercase"
ml="2"
>
{country.capital} •
{country.timezones &&
country.timezones.map((timezone) => (
<span key={timezone._id}>{timezone.name}</span>
))}
</Box>
</Box>
<Box mt="1" fontWeight="semibold" as="h4" lineHeight="tight" isTruncated>
{country.name}
</Box>
<Box>
{country.populationDensity}
<Box as="span" color="gray.600" fontSize="sm">
/ sq.km
</Box>
</Box>
{country.officialLanguages &&
country.officialLanguages.map((language) => (
<Box as="span" color="gray.600" fontSize="sm" key={language._id}>
<span>{language.name}</span>
</Box>
))}
</Box>
</Box>
);
export default Country;
All we did in the above was destructure country
from the component props and used the Box
component given us by Chakra UI to make the UI.
*Step 11: * Display the data and error component
Replace pages/index.js
with the code below:
import Head from "next/head";
import { Heading, Grid, Alert, AlertIcon } from "@chakra-ui/core";
import { request } from "graphql-request";
import useSWR from "swr";
import Layout from "../components/layout";
import Country from "../components/country";
const API_ENDPOINT = "https://countries-274616.ew.r.appspot.com/";
const countriesQuery = `query getCountries{
Country{
_id
name
capital
populationDensity
currencies {
_id
code
}
timezones {
_id
name
}
officialLanguages {
_id
name
}
flag {
_id
svgFile
}
}
}`;
export default function Home() {
const { data: countries, error } = useSWR(countriesQuery, (query) =>
request(API_ENDPOINT, query)
);
return (
<>
<Head>
<title>Countries</title>
</Head>
<Layout>
<Heading size="2xl" as="center">
Countries
</Heading>
{error && (
<Alert status="error">
<AlertIcon />
There was an error processing your request
</Alert>
)}
<Grid templateColumns="repeat(3, 1fr)" ml="10" mr="10" gap={6}>
{countries && countries.Country &&
countries.Country.map((country) => <Country country={country} key={country._id} />)}
</Grid>
</Layout>
</>
);
}
Run the app with yarn run dev
or npm run dev
.
You should see a list of countries, maps and their details listed.
In the next post, we will implement search functionality to demonstrate passing variables to GraphQL.
Full code available here on Github
Thanks for reading. Please, leave your comment in the feedback.
Top comments (3)
Thanks, Abiodun! But your app is not rendering on the server-side, right? We can see clearly a blank page showing up before the country flags appear. I guess (might be wrong), but useSWR is designed to work on the client-side, although I saw some workarounds to make it work on the server-side by passing the 'initialData' attribute.
[Solved] after npm i graphql
I get the following error. I installed graphql
Failed to compile
./node_modules/graphql-request/dist/index.js
Module not found: Can't resolve 'graphql/language/printer' in ...
next post URL Please ..