Frontend Serverless with React and GraphQL

Start at the beginning and work your way through this project. The code for each step as well as the finished project can be found in the Github repository.


17. Add Recipe page

Objective: Create the page that we will use for single recipe pages.

Now that we have a working Recipes Page, let's create the single Recipe Page. We will get here by clicking on a Recipe card from the Recipes Page. Next.js 9 has a feature where you can do limited routing based on how files are stored in the pages directory. Here are a few rules:

A file called recipe.tsx in the root of the pages directory will create a route at /recipe. A file called index.tsx in the pages/recipe folder will also create a route at /recipe. A file called [id].tsx in the pages/recipe folder will create a dynamic route where it will feed the id like this /recipe/:id in the path and it will create a paramter called id that it will passs as an initialProps into the component in the [id].tsx file. We will use this feature below:

pages/recipe/[id].tsx

import { useQuery } from '@apollo/react-hooks';
import { recipeGraphQL } from '../../graphql/queries/recipe';
import * as _ from 'lodash';
import { Loading } from '../../components/notify/Loading';
import { MainLayout } from '../../components/layout/MainLayout';
import { Error } from '../../components/notify/Error';
const Recipe = ({ id }) => {
const { loading, data, error } = useQuery(recipeGraphQL, {
variables: { where: { id } },
});
const title = _.get(data, 'recipe.title');
if (loading) {
return (
<MainLayout title="Recipe Loading">
<Loading />
</MainLayout>
);
}
if (error) {
return (
<MainLayout title="Recipe Loading Error">
<Error errorText={`${error}`} />
</MainLayout>
);
}
if (!title) {
return (
<MainLayout title="Not a valid recipe">
<Error errorText={`Not a valid recipe`} />
</MainLayout>
);
}
return (
<MainLayout title={title}>
<p>{title}</p>
</MainLayout>
);
};
Recipe.getInitialProps = ({ query }) => {
const { id } = query;
return { id };
};
export default Recipe;

We can use this parameter feature from naming the file [id].tsx to pass the id into our Recipe component. We then will run a query for a recipe based on that id and we can render different MainLayout's based on what condition the component is under. We are using the <MainLayout> so that we an appropriately label the title in the head of the document appropriately.

In the case where everything is loaded, for now we simply display the recipe title. We will expand this out later to actually add our recipe, but this is a good start.