Cooking has always been an essential part of our lives, and with the increasing demand for convenience and ease, recipe apps have become a go-to for many people. These apps provide access to a wide variety of recipes and enable users to easily plan, organize, and prepare their meals.

If you are interested in building your own recipe app, using ReactJS and the Edamam API can help you get started quickly and easily. ReactJS is a popular JavaScript library for building user interfaces, while the Edamam API provides an extensive recipe database that you can use to populate your app with delicious recipes.

In this article, we will guide you through the process of building a recipe app using ReactJS and the Edamam API. We will cover everything from setting up the project to implementing search and filtering functionality, as well as exploring additional features that can be added to your app.

By the end of this article, you will have a fully functional recipe app that you can customize and add to your portfolio. Whether you are a beginner or an experienced developer, this article will provide you with the knowledge and tools you need to get started with ReactJS and API integration. So let's get started!

Setting Up the Project:

In this section, we will guide you through the process of setting up a ReactJS project using Create React App. We will also explain how to install the necessary dependencies and create a basic file structure for your app.

Step 1: Installing Node.js and NPM

Before we can start building our recipe app with ReactJS, we need to make sure that we have Node.js and NPM (Node Package Manager) installed on our machine. Node.js is a JavaScript runtime that allows us to run JavaScript outside of a web browser, while NPM is a package manager for Node.js that helps us manage dependencies.

To check if Node.js is installed on your machine, open a terminal window and type the following command:

node -v

This should display the version of Node.js that is installed on your machine. If Node.js is not installed, you can download it from the official website.

Step 2: Creating a New React App with Create React App

Create React App is a command-line tool that allows us to quickly and easily create a new React app with a pre-configured setup. To create a new React app, open a terminal window and type the following command:

npx create-react-app my-recipe-app

This command creates a new React app named "my-recipe-app" in a new directory with the same name. The npx command is used to execute Create React App without installing it globally.

Step 3: Installing Dependencies

Once the app has been created, navigate to the project directory by typing the following command in the terminal:

cd my-recipe-app

Next, we need to install the necessary dependencies for our app. To do this, type the following command in the terminal:

npm install axios @material-ui/core @material-ui/icons

This command installs the axios library for making HTTP requests, as well as the @material-ui/core and @material-ui/icons libraries for styling our app with Material UI components.

Step 4: Creating a Basic File Structure

Now that we have installed the necessary dependencies, let's create a basic file structure for our app. The file structure should look something like this:

my-recipe-app/

├── public/

│   ├── index.html

│   └── favicon.ico

├── src/

│   ├── App.js

│   ├── index.js

│   ├── components/

│   │   ├── SearchBar.js

│   │   ├── RecipeCard.js

│   │   └── RecipeDetail.js

│   ├── utils/

│   │   └── api.js

│   └── styles/

│       ├── App.css

│       ├── SearchBar.css

│       ├── RecipeCard.css

│       └── RecipeDetail.css

└── package.json

  • The public directory contains the index.html file and the favicon.ico file.
  • The src directory contains the App.js and index.js files, which are the entry points for our app. It also contains the components, utils, and styles directories.
  • The components directory contains the React components that we will create for our app.
  • The utils directory contains the api.js file, which is where we will define our API requests.
  • The styles directory contains the CSS files for each of our components.

Congratulations! You have now set up a ReactJS project using Create React App and installed the necessary dependencies. In the next section, we will explore how to work with the Edamam API to fetch recipe data for our app.

Working with the Edamam API:

In this section, we will explore the Edamam API and its features. We will explain how to sign up for an API key and how to use it in our app to fetch recipe data. We will also provide a code snippet that shows how to fetch data from the API, and explain how to handle errors and display loading indicators while fetching data.

What is the Edamam API?

The Edamam API is a recipe search and nutrition analysis API that provides access to over 2 million recipes from a variety of sources. It also provides nutritional data for each recipe, such as calories, fat, and protein content. The API is easy to use and has a range of features, including ingredient and nutrient analysis, recipe and nutrition search, and recipe recommendation.

Signing Up for an API Key

To use the Edamam API in our app, we need to sign up for an API key. The process is straightforward and can be completed on the Edamam website. Follow these steps to sign up:

  1. Go to the Edamam API website (https://developer.edamam.com/) and create an account.
  2. Once you have created an account, sign in and navigate to the dashboard.
  3. Click on the "Applications" tab and create a new application.
  4. Give your application a name and description, and select the "Recipe Search API" option.
  5. Once your application has been created, you will be provided with an Application ID and an Application Key. Keep these somewhere safe, as we will need them later in our app.

Fetching Recipe Data from the Edamam API

To fetch recipe data from the Edamam API, we will use the axios library to make HTTP requests. The API endpoint we will use is:

https://api.edamam.com/search

To fetch recipe data, we need to make a GET request to this endpoint and pass in our API key, as well as any search parameters we want to use. Here is a code snippet that shows how to fetch recipe data from the API:

import axios from 'axios';

 

const API_ID = 'YOUR_API_ID';

const API_KEY = 'YOUR_API_KEY';

 

export const searchRecipes = async (query) => {

  try {

    const response = await axios.get('https://api.edamam.com/search', {

      params: {

        q: query,

        app_id: API_ID,

        app_key: API_KEY,

        from: 0,

        to: 9,

      },

    });

    return response.data.hits;

  } catch (error) {

    console.error(error);

  }

};

In this code snippet, we define a searchRecipes function that takes a query parameter and makes a GET request to the Edamam API search endpoint. We pass in our API ID and API key as query parameters, as well as the from and to parameters, which determine the range of results we want to fetch.

Handling Errors and Displaying Loading Indicators

While fetching data from the API, it's important to handle any errors that might occur and display loading indicators to the user. Here is an updated code snippet that shows how to handle errors and display loading indicators:

import axios from 'axios';

 

const API_ID = 'YOUR_API_ID';

const API_KEY = 'YOUR_API_KEY';

 

export const searchRecipes = async (query) => {

  try {

    // Set loading to true while we fetch data

    setLoading(true);

    const response = await axios.get('https://api.edamam.com/search', {

      params: {

        q: query,

        app_id: API_ID,

        app_key: API_KEY,

        from: 0,

        to: 9,

      },

    });

    // Set loading to false once we've fetched data

    setLoading(false);

    return response.data.hits;

  } catch (error) {

    // Set loading to false if there's an error

    setLoading(false);

    console.error(error);

  }

};

In this updated code snippet, we have added a setLoading function to set the loading state to true before making the API request, and to false once we have fetched the data or encountered an error. This allows us to display a loading indicator to the user while the data is being fetched.

We have also added an error handling block to catch any errors that might occur while making the API request. If an error occurs, we set the loading state to false and log the error to the console.

By handling errors and displaying loading indicators, we can provide a better user experience for our app users.

Designing the User Interface

Good user interface design is crucial for recipe apps as it can make the app more user-friendly and visually appealing. A well-designed app can improve the user experience, making it easier for users to find and save recipes, and ultimately increasing engagement and usage.

To style our recipe app, we can use CSS and Material UI, which is a popular UI library for React that provides pre-designed components and styles.

To use Material UI in our app, we first need to install the necessary packages:

npm install @material-ui/core @material-ui/icons

Next, we can import the components we need and use them to style our app. Here's an example of how we can use Material UI to style our search bar:

import React from 'react';

import { makeStyles } from '@material-ui/core/styles';

import InputBase from '@material-ui/core/InputBase';

import SearchIcon from '@material-ui/icons/Search';

 

const useStyles = makeStyles((theme) => ({

  search: {

    position: 'relative',

    borderRadius: theme.shape.borderRadius,

    backgroundColor: theme.palette.common.white,

    '&:hover': {

      backgroundColor: theme.palette.common.white,

    },

    marginRight: theme.spacing(2),

    marginLeft: 0,

    width: '100%',

    [theme.breakpoints.up('sm')]: {

      marginLeft: theme.spacing(3),

      width: 'auto',

    },

  },

  searchIcon: {

    padding: theme.spacing(0, 2),

    height: '100%',

    position: 'absolute',

    pointerEvents: 'none',

    display: 'flex',

    alignItems: 'center',

    justifyContent: 'center',

  },

  inputRoot: {

    color: 'inherit',

  },

  inputInput: {

    padding: theme.spacing(1, 1, 1, 0),

    // vertical padding + font size from searchIcon

    paddingLeft: `calc(1em + ${theme.spacing(4)}px)`,

    transition: theme.transitions.create('width'),

    width: '100%',

    [theme.breakpoints.up('md')]: {

      width: '20ch',

    },

  },

}));

 

function SearchBar() {

  const classes = useStyles();

 

  return (

    <div className={classes.search}>

      <div className={classes.searchIcon}>

        <SearchIcon />

      </div>

      <InputBase

        placeholder="Search for a recipe..."

        classes={{

          root: classes.inputRoot,

          input: classes.inputInput,

        }}

        inputProps={{ 'aria-label': 'search' }}

      />

    </div>

  );

}

 

export default SearchBar;

In this example, we're using the makeStyles function from Material UI to define the styling for the search bar. We're using a combination of CSS properties and Material UI styles to create the search bar's appearance and functionality.

We're also using Material UI's InputBase and SearchIcon components to create the input field and search icon. We're passing in classes and inputProps as props to the InputBase component to apply the custom styling we defined using makeStyles.

Overall, Material UI provides an easy and efficient way to style our app and create a consistent and professional-looking user interface.

Implementing Search and Filtering Functionality

Now that we have a basic recipe app, let's improve the user experience by implementing search and filtering functionality. The Edamam API provides several search and filtering features that we can use to allow users to find recipes that meet their specific needs.

To use the search and filtering features, we'll need to modify the URL that we use to fetch recipe data from the API. Here's an example of how to modify the URL to search for recipes that include the keyword "chicken" and have a maximum of 500 calories per serving:

const searchUrl = `https://api.edamam.com/search?q=${query}&app_id=${APP_ID}&app_key=${APP_KEY}&from=${startIndex}&to=${endIndex}&calories=max%20500`;

In this example, we've added the calories=max%20500 parameter to the URL to filter the results based on the maximum number of calories per serving.

To implement search and filtering in the app, we'll need to create UI components for users to enter search keywords and select filtering options. Here's an example of how to create a search bar component:

import React, { useState } from 'react';

import { TextField, Button } from '@material-ui/core';

 

const SearchBar = ({ onSearch }) => {

  const [searchQuery, setSearchQuery] = useState('');

 

  const handleInputChange = (event) => {

    setSearchQuery(event.target.value);

  };

 

  const handleSearch = () => {

    onSearch(searchQuery);

  };

 

  return (

    <div>

      <TextField

        label="Search for recipes"

        variant="outlined"

        value={searchQuery}

        onChange={handleInputChange}

      />

      <Button variant="contained" color="primary" onClick={handleSearch}>

        Search

      </Button>

    </div>

  );

};

 

export default SearchBar;

In this example, we're using the TextField and Button components from Material UI to create a search bar with an input field and a search button. We're also using the useState hook to manage the state of the search query.

To implement filtering, we can create UI components for users to select filtering options and then modify the URL that we use to fetch recipe data from the API based on the selected options.

When designing search and filtering interfaces, it's important to consider the user's goals and the context in which they are using the app. Some best practices for designing search and filtering interfaces include:

  • Providing clear and concise instructions for how to use the search and filtering features
  • Using appropriate input fields and UI components for the type of data being searched or filtered (e.g., dropdown menus for selecting options)
  • Providing feedback to the user when they perform a search or apply a filter (e.g., displaying a loading indicator or a message indicating the number of results found)
  • Allowing users to refine their search or filter criteria without having to start over from the beginning.

Adding Additional Features

So far, we've built a functional recipe app with the ability to search for and display recipes from the Edamam API. However, there are many additional features that we could add to make the app even more useful for users. In this section, we'll discuss some of these features and provide an example of how to implement one of them.

  1. User Authentication: 

By adding user authentication, users could save their favorite recipes and access them later. We could use a service like Firebase Authentication to handle user authentication and create a database to store users' favorite recipes. Here's an example of how to use Firebase Authentication in our app:

import firebase from "firebase/app";

import "firebase/auth";

 

// Initialize Firebase

const firebaseConfig = {

  // your firebase config here

};

firebase.initializeApp(firebaseConfig);

 

// Sign up a new user

const signUp = async (email, password) => {

  try {

    const result = await firebase.auth().createUserWithEmailAndPassword(email, password);

    return result.user;

  } catch (error) {

    console.error(error);

  }

};

 

// Log in an existing user

const logIn = async (email, password) => {

  try {

    const result = await firebase.auth().signInWithEmailAndPassword(email, password);

    return result.user;

  } catch (error) {

    console.error(error);

  }

};

 

// Log out the current user

const logOut = async () => {

  try {

    await firebase.auth().signOut();

  } catch (error) {

    console.error(error);

  }

};

  1. Favoriting Recipes: 

To allow users to favorite recipes, we could add a heart icon to each recipe card. When the user clicks on the heart icon, we could add the recipe to the user's favorites list. Here's an example of how to implement this feature:

import { useState } from "react";

import { IconButton } from "@material-ui/core";

import { Favorite, FavoriteBorder } from "@material-ui/icons";

 

const RecipeCard = ({ recipe, onFavorite }) => {

  const [isFavorite, setIsFavorite] = useState(false);

 

  const handleFavoriteClick = () => {

    setIsFavorite(!isFavorite);

    onFavorite(recipe);

  };

 

  return (

    <Card>

      <CardMedia image={recipe.image} title={recipe.label} />

      <CardContent>

        <Typography variant="h6">{recipe.label}</Typography>

        <Typography variant="body2">{recipe.source}</Typography>

      </CardContent>

      <CardActions>

        <IconButton onClick={handleFavoriteClick}>

          {isFavorite ? <Favorite /> : <FavoriteBorder />}

        </IconButton>

      </CardActions>

    </Card>

  );

};

In this example, we're using the useState hook to keep track of whether the recipe is favorited or not. When the user clicks on the heart icon, we toggle the isFavorite state and call the onFavorite function, which adds the recipe to the user's favorites list.

  1. Sharing Recipes on Social Media:

To implement the sharing feature, we'll use the Material-UI IconButton component to display the social media icons, and the react-share library to handle the sharing functionality.

First, let's install the react-share library:

npm install react-share

Then, we'll import the IconButton and ShareButton components:

import IconButton from '@material-ui/core/IconButton';

import { FacebookShareButton, TwitterShareButton } from 'react-share';

Next, we'll add the social media icons to the recipe card:

<CardActions>

  <IconButton>

    <FacebookShareButton url={recipe.url} quote={recipe.label}>

      <FacebookIcon size={32} round={true} />

    </FacebookShareButton>

  </IconButton>

  <IconButton>

    <TwitterShareButton url={recipe.url} title={recipe.label}>

      <TwitterIcon size={32} round={true} />

    </TwitterShareButton>

  </IconButton>

</CardActions>

In this example, we're displaying Facebook and Twitter icons, and using the FacebookShareButton and TwitterShareButton components from the react-share library to handle the sharing functionality. We're passing in the recipe URL and label as props to pre-populate the share dialog.

Now, when the user clicks on a social media icon, a share dialog will open with the recipe name and link pre-populated.

Note: You'll need to register your app with Facebook and Twitter to get API keys and enable sharing on those platforms. You can find more information on how to do this in the react-share documentation.

Conclusion:

In this article, we have explored how to build a recipe app with ReactJS and the Edamam API. We have covered how to set up the project, fetch data from the API, design the user interface using CSS and Material UI, and add search and filtering functionality to the app. We have also discussed possible additional features that could be added to the app, such as user authentication and social media sharing.

By following the steps outlined in this article, you can build a fully functional recipe app that provides users with a great user experience and access to a vast library of recipes.

If you want to build a recipe app or any other type of web application using ReactJS, you may need to hire reactjs developer with experience in building similar apps. You can find ReactJS developers on various freelance platforms or reach out to ReactJS development companies that specialize in building custom web applications. With the right team of ReactJS developers, you can bring your app idea to life and create a successful product that meets the needs of your users.