Gatsby.js is a modern site generator built for React. This utility allows you to get up and running in blazingly fast time, through the use of a few simple commands. Gatsby allows you to leverage Facebook’s ultra-popular JavaScript framework in order to put out stylish websites for users to enjoy. This article will provide you with the steps to build a simple recipe retrieval application as a means of walking you through how to leverage Gatsby.js.
In order to utilize Gatsby commands, you must first install the Gatsby-cli globally on your local machine. Run the following command to do just that:
{% code-block language="js" %}
$ npm install -g gatsby-cli
{% code-block-end %}
Once that’s finished running, you’ll be able to use the full slate of gatsby.js commands from the terminal.
You can now immediately initialize a new gatsby.js project by entering the following command:
{% code-block language="js" %}
gatsby new <your-site-name-here> https://github.com/gatsbyjs/gatsby-starter-hello-world
{% code-block-end %}
This command results in the following file structure:
{% code-block language="js" %}
├── node_modules
├── src
├── .gitignore
├── .prettierrc
├── gatsby-browser.js
├── gatsby-config.js
├── gatsby-node.js
├── gatsby-ssr.js
├── LICENSE
├── package-lock.json
├── package.json
└── README.md
{% code-block-end %}
The package.json file as seen below delineates a list of commands that can now be used inside the project in order to carry out various functions in the development process.
{% code-block language="js" %}
{
"name": "gatsby-starter-default",
"private": true,
"description": "A simple starter to get up and developing quickly with Gatsby",
"version": "0.1.0",
"author": "Kyle Mathews <mathews.kyle@gmail.com>",
"dependencies": {
"gatsby": "^2.25.1",
"gatsby-image": "^2.4.21",
"gatsby-plugin-manifest": "^2.5.1",
"gatsby-plugin-offline": "^3.3.1",
"gatsby-plugin-react-helmet": "^3.3.14",
"gatsby-plugin-sharp": "^2.7.0",
"gatsby-source-filesystem": "^2.4.0",
"gatsby-transformer-sharp": "^2.5.21",
"prop-types": "^15.7.2",
"react": "^16.12.0",
"react-dom": "^16.12.0",
"react-helmet": "^6.1.0"
},
"devDependencies": {
"prettier": "2.1.2"
},
"keywords": [
"gatsby"
],
"license": "0BSD",
"scripts": {
"build": "gatsby build",
"develop": "gatsby develop",
"format": "prettier --write \"**/*.{js,jsx,ts,tsx,json,md}\"",
"start": "npm run develop",
"serve": "gatsby serve",
"clean": "gatsby clean",
"test": "echo \"Write tests! -> https://gatsby.dev/unit-testing\" && exit 1"
},
"repository": {
"type": "git",
"url": "https://github.com/gatsbyjs/gatsby-starter-default"
},
"bugs": {
"url": "https://github.com/gatsbyjs/gatsby/issues"
}
}
{% code-block-end %}
The following command is entered into the terminal from the project directory to fire up the development server.
{% code-block language="js" %}
$ gatsby develop
{% code-block-end %}
Then, the following command is entered in order to create a production build.
{% code-block language="js" %}
$ gatsby build
{% code-block-end %}
Lastly, the following command is entered in order to serve a local production build of your project.
{% code-block language="js" %}
$ gatsby serve
{% code-block-end %}
Out of the box, Gatsby provides the ability to quickly add new pages to your site. As seen in the “pages” folder, three default pages exist for you to edit or delete as you see fit. Any additional react.js file added in this folder will get automatically rendered as a new page in your site. Then navigating between them would simply be a case of adding the appropriate “href” property to a link tag.
Gatsby also pre-packages several components that assist with the layout and SEO of your website. The default “layout” component (as seen below);
{% code-block language="js" %}
import React from "react"
import PropTypes from "prop-types"
import { useStaticQuery, graphql } from "gatsby"
import Header from "./header"
import "./layout.css"
const Layout = ({ children }) => {
const data = useStaticQuery(graphql`
query SiteTitleQuery {
site {
siteMetadata {
title
}
}
}
`)
return (
<>
<Header siteTitle={data.site.siteMetadata?.title || `Title`} />
<div
style={{
margin: `0 auto`,
maxWidth: 960,
padding: `0 1.0875rem 1.45rem`,
}}
>
<main>{children}</main>
<footer style={{
marginTop: `2rem`
}}>
(c) {new Date().getFullYear()}, Built with
{` `}
<a href="https://www.gatsbyjs.com">Gatsby</a>
</footer>
</div>
</>
)
}
Layout.propTypes = {
children: PropTypes.node.isRequired,
}
export default Layout
{% code-block-end %}
Can be edited as you see fit and is imported in each page to be displayed in the site. The “SEO” component is also exported from its original component file. It can be edited appropriately to represent the exact parameters required for each page, and for the website as a whole. These principles can be put into practice to build a one-page web app.
To demonstrate this, let’s walk through the steps to building a recipe app that utilizes Gatsby and the Spoonacular API to display recipes for any dish. To start, a simple search form component can be built in the components folder. This search form receives two props from the parent component, the handleChange and handleSubmit props, as seen below.
handleChange updates the parent component’s state based on the entry made to the form and the handleSubmit prop defines the logic that is carried out once the submit button is pressed.
{% code-block language="js" %}
import React from 'react';
import Proptypes from 'prop-types';
const Search = ({ handleSubmit, handleChange }) => (
<form
onSubmit={handleSubmit}
>
<label htmlFor="recipe">
Search recipe:
<br />
<input
type="text"
id="recipe-input"
name="recipe"
onChange={handleChange}
required
/>
</label>
<br />
<label htmlFor="total">
How many recipes do you wish to generate:
<br />
<input
type="number"
id="total"
name="total"
min="1"
max="100"
onChange={handleChange}
required
/>
</label>
<br />
<button
type="submit"
>
Search
</button>
</form>
);
Search.propTypes = {
handleSubmit: Proptypes.func.isRequired,
handleChange: Proptypes.func.isRequired,
};
export default Search;
{% code-block-end %}
This component is exported at the bottom of the file and imported into the “index.js” file in the pages folder. The index.js file represents the homepage in any Gatsby project. In the case of one-page projects, you simply import your components into this page and edit it as you see fit.
With respect to editing the index page, define the components state and bindings for the handleChange and handleSubmit functions.
{% code-block language="js" %}
class IndexPage extends React.Component {
constructor(props) {
super(props);
this.state = {
entry: '',
total: 1,
recipes: [],
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
}
{% code-block-end %}
‘Entry’ stores the name of the recipe, ‘total’ is the number of different recipes you want to return from the API and the ‘recipes’ array is in place to store the results returned.
The handleChange function updates the state values based on which field is entered into using the “setState” function as follows:
{% code-block language="js" %}
handleChange(e) {
const { value, id } = e.target;
if (id === 'recipe-input') {
this.setState({ entry: value });
} else {
this.setState({ total: value });
}
}
{% code-block-end %}
The handleSubmit utilizes the axios npm package to make a GET request to the API and updates the component’s state once the response is received.
{% code-block language="js" %}
handleSubmit(e) {
e.preventDefault();
const { entry, total } = this.state;
const apiKey = '<your API key here>';
axios({
method: 'get',
url: `https://api.spoonacular.com/recipes/search?&apiKey=${apiKey}&query=${entry}&number=${total}`,
})
.then(response => {
this.setState({ recipes: response.data.results });
});
}
{% code-block-end %}
When organizing how your results are displayed, you can utilize the map function to iterate over the “recipes” array and display your results on the page. Below, you can see an example of how the results can be displayed to the user.
{% code-block language="js" %}
render() {
const { recipes } = this.state;
return (
<Layout>
<SEO title="Home" />
<div>
<div className="title-section">
<Search
handleChange={this.handleChange}
handleSubmit={this.handleSubmit}
/>
</div>
</div>
<h2>Your Recipes</h2>
<div id="recipe">
{recipes.map(recipe => (
<div key={recipe.id} className="recipe-area">
<div className="recipe-img">
<img src={`https://spoonacular.com/recipeImages/${recipe.id}-240x150.jpg`} alt="recipe depiction" />
</div>
<div className="recipe-desc">
<h2>{recipe.title}</h2>
<p>
This recipe takes
{' '}
{recipe.readyInMinutes}
{' '}
minutes to prepare.
</p>
<p>
This recipe makes
{' '}
{recipe.servings}
{' '}
{recipe.servings === 1 ? 'serving.' : 'servings.'}
</p>
<p>
Click
{' '}
<a
href={recipe.sourceUrl}
target="_blank"
rel="noopener noreferrer"
>
here
</a>
{' '}
to see the full recipe instructions
</p>
</div>
</div>
))}
</div>
</Layout>
);
}
{% code-block-end %}
As you can see, the results are configured inside of the imported Layout component that Gatsby gives users out of the box. The SEO component is also used and is passed in a “title” prop which will be displayed on the tab in the browser.
So, there you have it. Gatsby allows us to get up and running in no time in order to put together clean web apps. I hope this introduction helps you to get up and running with it in no time. And check out the repo for this small project here. Happy coding!
Photo by Sam Browne on Unsplash
Career advice, the latest coding trends and languages, and insights on how to land a remote job in tech, straight to your inbox.