Tutorial for React Beginners - Building A Recipe Book In React

Emma Bostian
Level Up Coding
Published in
9 min readAug 15, 2018

--

Introduction

When I started learning React, I found it difficult to keep up sometimes. I found that some of the tutorials were a bit too fast-paced for my liking.

Thus, I’ve decided to write my own step-by-step tutorial on how to create a recipe book using React.

This will include the basics of using create-react-app and won’t use many fancy packages.

I don’t claim to be a React expert (I’m still learning myself), so if you find a mistake, feel free to leave a comment! 😸

Pre-Requisities

  1. Download npm

We use Node Package Manager (NPM) to download and manage packages in our application.

2. Install React and the React CLI

npm install -g react-cli react

We want to install React and the React Command Line Interface so we can use them to create React applications anywhere in our file system.

3. Install yarn

npm install homebrew
brew install yarn

Homebrew is another package manager that we need to install Yarn. We use Yarn to install package dependencies.

4. Install sass with

npm install -g sass

We’re using Syntactically Awesome Stylesheeets as our CSS pre-processor to make our styles modular and to get features which CSS doesn’t provide.

I’m using GitHub to host all of the code so feel free to fork/clone my repo and follow along!

Step 1: Project Architecture

All code can be found here.

  1. Using the command-line, CD into your project folder. I cloned my repository to my desktop so my command looks like this:
cd Desktop/react-recipes

2. Once inside the project directory run the following command.

create-react-app .

This creates a React application in your already established directory. To create a new application without a project folder, run:

create-react-app name-of-app

3. Once create-react-app has finished, install the dependencies with:

yarn

4. Now, we’ll open the app in your IDE of choice (I enjoy VS Code) and start the the application.

Once you open your project in your IDE, this is what your src/ folder will look like.

Run yarn start in the command line to see the default create-react-app landing page.

5. Next, delete the files we won’t be using:App.css, App.test.js, index.css, and logo.svg.

I like my components to be modularized, so let’s go ahead and add some folders to structure our app.

Create a components folder in src/ and move App.js inside.

Your src/ folder structure should now look like this.

6. Update index.js to point to the new path ofApp.js and remove old imports for files we just deleted.

7. Inside App.js remove old imports and the default code you get with create-react-app.

Setting Up Sass

Here is a quick and easy way to use Sass in your project without ejecting!

  1. Create a styles/ folder in src/ and add two folders inside of that: scss/ and css/. Inside of the scss/ folder, add two more folders: base/ and components/ . Also add an index.scss file inside of the scss/ folder.

2. Update index.js to include a path to index.css (which we haven’t generated yet). It will live inside the src/styles/css folder.

3. Now, let’s add a few styles to see the transpilation of Sass (SCSS) to CSS.

  • Inside styles/base/, create _variables.scss and _elements.scss. The elements partial will contain any styling to base HTML elements such as <body>, <h1>, etc. and the variables partial will contain our variables for fonts, colors, etc.

Partials in Sass are snippets of Sass code which you can include in other Sass files. We’re creating a partial for variables and base elements so we can keep each type of styling separate. We will import each partial into the index.scss file in order to use it within our HTML file. Partials are denoted by an underscore in the file name (although you can omit this during import).

I am including a Google font in the index.html file, and I cleaned up some of the create-react-app default comments. I also updated the title of the app.

  • Once including the custom font link in the index.html file, create two variables $color-main and $font-main inside src/styles/scss/base/_variables.scss.

4. Inside styles/scss/base/_elements.scss, set the <h1> background-color and font-family.

5. Inside styles/scss/index.scss, import the partials.

Now, let’s use Sass watch to transpile the Sass code (SCSS) to CSS!

6. In package.json, create a new script:

"sass" : "sass --watch src/styles/scss:src/styles/css"

This will take any Sass (SCSS) file found in src/styles/scss and transpile it to CSS code in src/styles/css.

7. In the terminal, run yarn run sass. This will transpile index.scss into index.css and index.css.map.

8. Run yarn start to see your newly created App!

Step 2: Recipe Component

We’re going to use two additional components for this application: navigation, and recipe.

Let’s start with the Recipe component.

  1. Inside src/components create a new file called Recipe.js. Import React . and Component, and include the export statement at the end of the file.

2. We want to be able to pass data through (as props) to our Recipe component. So let’s create an array of Recipes in the state, which will live inside of App.js.

  • Create a constructor function and call super();

What kinds of information do we need to keep track of in our state for each recipe?

  • ingredients: string []
  • steps: string []
  • title: string
  • id: string
  • Create this.state in the constructor and add two items to our recipes array.

The id for each recipe ideally should go through a function which ensures its uniqueness, but for simplicity’s sake we’ll just set it explicitly.

You can additionally choose to get rid of .bind(this) but I kept it here for simplicity’s sake.

3. In order to check the type of the data passed through to the Recipe component, we are going to use PropTypes. We want to ensure the data we receive is the type of data we expect.

npm install prop-types --save
  • Import PropTypes to Recipe.js.
  • At the bottom of the component, before the export, add a propTypes key with the corresponding properties we’re going to be passing in: ingredients, steps, title, and id. I have set the isRequired flag on these because we don’t want to show a recipe without any of them.
  • Create two constants, ingredients and steps, before the return() statement in the render function. These will create new list items for each item in the ingredients and steps array. You can do this in the JSX, but I like to extract my logic into variables.
  • Add HTML elements for the title, the Ingredients and Steps headers, and display the list of ingredients and steps we just created above with const.

Here is what Recipe.js should look like:

4. Back in App.js, let’s iterate through each of the Recipes and actually pass the data.

This will create a new <Recipe /> component for each recipe in the state.

Here is what App.js looks like:

You should now see each of your recipes listed with their respective ingredients and steps.

It doesn’t look super pretty yet, but it works!

Step 3: Navigation Component

  1. Inside the components/ folder, create Navigation.js.

The Navigation component, for now, only requires one prop: the list of recipes.

2. Include the Navigation component in App.js

  • Inside App.js, import Navigation.js and include it in the render() function.
  • Add a recipes prop and pass the list of recipes from the state.

3. Back in Navigation.js, let’s render the recipes as buttons.

  • Loop through each recipe in the array and dynamically generate an element.

4. Now, let’s develop the logic for showing the correct recipe when its respective navigation button is pressed.

  • In App.js, create a new state called selectedRecipe. This will contain the id of the recipe that’s currently being shown. We can set the initial state to null for now.
  • Inside of the render function, we only want to create a <Recipe> component for the recipe which is currently selected. We can use the array.filter() function for this.

This works great, except that our initial state value for selectedRecipe is null, so let’s wrap the above statement in an `if` statement to ensure that `this.state.selectedRecipe` is defined.

if(this.state.selectedRecipe) {...}

Additionally, the filter() function returns an array of items fitting that description. So let’s introduce a local variable called recipeToSelect.

We’ll declare it before the if() statement we just wrote, and if the filteredRecipes returned at least one item, we’ll assign it to the first value found (it should only return one, so this is more of an edge-case check).

Now, we can check if recipeToSelect has a value. If it does, render the <Recipe> component with that id, otherwise, just return null.

5. Next, we want to initialize our app with the first recipe, so let’s add a componentDidMount() lifecycle function.

If there is a recipe in the recipes state array, set the state of selectedRecipe to its id.

7. The last thing we need to do is update which recipe is shown when a navigation button is clicked.

Inside App.js, let’s create a function which sets the selectedRecipe state to the selected recipe.

Underneath the constructor, add a function called selectNewRecipe. This will take one argument recipeId and update the state if this value exists.

This looks great, except for one thing: we need to bind this function to App. Otherwise the this context will be all wrong.

Inside the constructor, add a binding for selectNewRecipe.

Cool! So how do we get the child component (Navigation) to call this function when a button is clicked?

  • Pass this function as a prop to Navigation.

We have just created a reference to this function in the form of a prop.

  • Inside Navigation.js, let’s add an onClick handler to the buttons.

When each button is clicked, it will call the changeRecipe function. So let’s create that now.

This function will take in the e (event) and grab the id for the clicked Recipe. Then, it will pass this id to the parent function in order to update the state.

And just as we did in App.js to bind the function, we have to do that here as well. So let’s create a constructor function and bind that value.

Also update propTypes in Navigation to include the passed function.

Awesome! Your app should now render the correct components!

Here are the completed files for App.js and Navigation.js:

And this is what our app currently looks like.

Step 4: Styles

Okay, I’ll admit, this app doesn’t look so pretty. So let’s give it some styles. You can style your app however you’d like. I just create a new scss partial for each component’s Sass and import it into index.scss.

Styling the Selected Navigation Item

One important thing we have to do is style the selected navigation item. To do this, we have to pass the selectedRecipe state to the <Navigation> component as a prop.

Next, add a ternary to the className attribute in Navigation.js. If the id of the navigation item is equal to the selected recipe, give it an active class in addition to the base class.

Here’s what our styled app looks like.

Conclusion

I know this isn’t a super fancy app, but it’s a great learning exercise for beginners to React.

I like this app idea, as well because I have a TON of recipes that I need to keep track of.

You can even host this through GitHub and send it to your friends and family!

Emma Wedekind is a Front-end Software Engineer at LogMeIn in Karlsruhe, Germany. She enjoys blogging, long walks on the beach and cats. Also pizza. Mmmm pizza.

If you enjoyed this blog be sure to give it a few claps or follow me on Twitter, LinkedIn, or Instagram! 😄 😼

--

--

Software Engineer @ LogMeIn by day, cat Mom by night. Also a full-time Bibliophile. I enjoy all things Front-end & Design