Building a Recipe Search App with React and Edamam API
This tutorial will guide you through the process of building a recipe search app using React and the Edamam API. We will start by setting up the project and installing necessary dependencies. Then, we will build the search component, handle user input, and make API requests. Next, we will display the search results, implement pagination, and add sorting and filtering options. Finally, we will fetch recipe details, display recipe information, and implement favorite functionality. Along the way, we will also cover styling the app using CSS frameworks, customizing styles, and considering responsive design.

Introduction
React is a popular JavaScript library for building user interfaces. It allows developers to create reusable UI components and efficiently update the DOM. The Edamam API is a powerful tool for accessing a vast collection of recipe data. By combining React with the Edamam API, we can create a recipe search app that provides users with an easy way to find and explore various recipes.
Setting Up the Project
Creating a new React project
To start building our recipe search app, we need to create a new React project. We can do this by using the create-react-app command-line tool. Open your terminal and run the following command:
npx create-react-app recipe-search-app
This will create a new directory called recipe-search-app with all the necessary files and dependencies for a React project.
Installing necessary dependencies
Next, we need to install the necessary dependencies for our project. Open your terminal, navigate to the recipe-search-app directory, and run the following command:
npm install axios react-router-dom
This will install the axios library, which we will use for making API requests, and the react-router-dom library, which we will use for routing within our app.
Setting up API credentials
Before we can start making API requests to the Edamam API, we need to obtain API credentials. Visit the Edamam Developer portal and sign up for a free account. Once you have an account, create a new application and you will be provided with an API key and an API ID. Take note of these credentials as we will need them later.
Building the Search Component
Creating the search form
In order to allow users to search for recipes, we need to create a search form component. Create a new file called SearchForm.js in the src directory and add the following code:
import React, { useState } from 'react';
const SearchForm = () => {
const [query, setQuery] = useState('');
const handleInputChange = (event) => {
setQuery(event.target.value);
};
const handleSubmit = (event) => {
event.preventDefault();
// Make API request using the query value
};
return (
<form onSubmit={handleSubmit}>
<input type="text" value={query} onChange={handleInputChange} />
<button type="submit">Search</button>
</form>
);
};
export default SearchForm;
In this code, we use the useState hook to create a state variable called query and a corresponding setter function called setQuery. The handleInputChange function updates the query state variable whenever the user types into the input field. The handleSubmit function is called when the form is submitted, preventing the default form submission behavior. Finally, we render a form element with an input field and a submit button, with the handleSubmit function as the form's onSubmit event handler.
Handling user input
Now that we have the search form component, we need to handle the user's search input and make API requests based on that input. To do this, we will create a new file called SearchPage.js in the src directory and add the following code:
import React, { useState } from 'react';
import SearchForm from './SearchForm';
import axios from 'axios';
const SearchPage = () => {
const [results, setResults] = useState([]);
const handleSearch = async (query) => {
try {
const response = await axios.get(
`https://api.edamam.com/search?q=${query}&app_id={YOUR_APP_ID}&app_key={YOUR_API_KEY}`
);
setResults(response.data.hits);
} catch (error) {
console.error(error);
}
};
return (
<div>
<h1>Recipe Search</h1>
<SearchForm onSearch={handleSearch} />
{/* Render search results */}
</div>
);
};
export default SearchPage;
In this code, we import the SearchForm component that we created earlier. We also import the axios library for making API requests. We use the useState hook to create a state variable called results and a corresponding setter function called setResults. The handleSearch function is called when the form is submitted, and it makes an API request to the Edamam API using the query value. The API response is then stored in the results state variable. Finally, we render the SearchForm component and display the search results.
Displaying Search Results
Rendering search results
Now that we have the search results stored in the results state variable, we can render them in our app. Modify the SearchPage component in the SearchPage.js file as follows:
import React, { useState } from 'react';
import SearchForm from './SearchForm';
import axios from 'axios';
const SearchPage = () => {
const [results, setResults] = useState([]);
const handleSearch = async (query) => {
try {
const response = await axios.get(
`https://api.edamam.com/search?q=${query}&app_id={YOUR_APP_ID}&app_key={YOUR_API_KEY}`
);
setResults(response.data.hits);
} catch (error) {
console.error(error);
}
};
return (
<div>
<h1>Recipe Search</h1>
<SearchForm onSearch={handleSearch} />
<ul>
{results.map((result) => (
<li key={result.recipe.uri}>
<h2>{result.recipe.label}</h2>
<img src={result.recipe.image} alt={result.recipe.label} />
<p>Source: {result.recipe.source}</p>
<p>Calories: {result.recipe.calories}</p>
{/* Add more recipe information */}
</li>
))}
</ul>
</div>
);
};
export default SearchPage;
In this code, we render an unordered list element (<ul>) to display the search results. We use the map function to iterate over the results array and render a list item (<li>) for each result. Inside each list item, we display the recipe label, image, source, and calories.
Handling pagination
The Edamam API provides pagination functionality, allowing us to retrieve a specific set of search results. To implement pagination in our app, we need to modify the SearchPage component in the SearchPage.js file as follows:
import React, { useState } from 'react';
import SearchForm from './SearchForm';
import axios from 'axios';
const SearchPage = () => {
const [results, setResults] = useState([]);
const [currentPage, setCurrentPage] = useState(0);
const handleSearch = async (query, page = 0) => {
try {
const response = await axios.get(
`https://api.edamam.com/search?q=${query}&app_id={YOUR_APP_ID}&app_key={YOUR_API_KEY}&from=${page * 10}`
);
setResults(response.data.hits);
setCurrentPage(page);
} catch (error) {
console.error(error);
}
};
const handlePagination = (direction) => {
const nextPage = direction === 'next' ? currentPage + 1 : currentPage - 1;
handleSearch(query, nextPage);
};
return (
<div>
<h1>Recipe Search</h1>
<SearchForm onSearch={handleSearch} />
<ul>
{results.map((result) => (
<li key={result.recipe.uri}>
<h2>{result.recipe.label}</h2>
<img src={result.recipe.image} alt={result.recipe.label} />
<p>Source: {result.recipe.source}</p>
<p>Calories: {result.recipe.calories}</p>
</li>
))}
</ul>
<button onClick={() => handlePagination('prev')} disabled={currentPage === 0}>
Previous
</button>
<button onClick={() => handlePagination('next')}>Next</button>
</div>
);
};
export default SearchPage;
In this code, we add a new state variable called currentPage to keep track of the current page of search results. The handleSearch function now accepts an optional page parameter, which is used to specify the starting index of the search results. We update the API request URL to include the from parameter, which is calculated based on the current page. We also add a new handlePagination function, which is called when the previous or next button is clicked. This function updates the currentPage state variable and calls the handleSearch function with the new page value. Finally, we render the previous and next buttons, disabling the previous button if we are on the first page.