React Basics

This comprehensive guide teaches students how to get started with REACT


React Basics

We will learn the basics of React. While doing this, we will build a recipe sharing application that will allow use to view recipes

Introduction to React

What is React?

React is a tool that helps developers build websites. Think of it like a box of LEGO bricks where each brick can be used to build different parts of your website. React has been made by Facebook and is used by many websites around the world to make their web pages interactive and dynamic.

Why Use React?

  • Simple to Work With

React helps you manage your website's appearance and behavior in a straightforward way. When something changes on your website (like a user clicking a button), React knows exactly which part of the display needs to be updated without reloading the entire page. This keeps your website fast and responsive.

  • Build with Pieces

In React, you build your website using "components." Imagine each component as a block or module that represents a part of your webpage. For example, one block might be a button, another might be a picture, and another could be a text box. You can reuse these blocks over different parts of your website, which makes it easier to build and manage.

  • Flexible

React is like playing with LEGO—it doesn’t matter what your base is; you can start putting pieces anywhere, and they’ll fit. This means you can add React to a small part of your existing website or build a whole new site from scratch.

Key Ideas in React

  • JSX

JSX stands for JavaScript XML. It's a way to write what you want your website to look like using a mix of HTML (the standard web language) and JavaScript (a programming language for websites). It looks like this:

const element = <h1>Hello, world!</h1>;

This code creates a heading on your website that says "Hello, world!".

  • Virtual DOM

React uses something called the "Virtual DOM" to keep your website speedy. DOM stands for Document Object Model, and it's like a tree diagram that describes the structure of your website. The Virtual DOM is a copy of this tree. React makes changes to this copy first, which is much faster than changing the real one. Once it's done, it updates the real DOM with only the necessary changes, which keeps your website fast.

  • Data Flow & State Management

React has a special way of handling data that ensures your webpage is consistent and behaves correctly. You can think of "state" as a snapshot of your page at any time (like what's written in a form, or whether a button is turned on or off). React makes sure that your webpage displays the right state at all times.

  • Lifecycle Methods

These are special functions in React that get called at specific points when your component is shown on the screen, updated, or removed. They're like hooks that let you run code at the right time. For example, you can set up a timer when a component appears or save data before it disappears.

  • Hooks

Hooks are tools in React that let you "hook into" React features like state and lifecycle methods without having to use classes. They make it easier to write your components and keep your code clean and understandable.

Getting Started with React

To start using React, you can insert it into a small part of an existing website or create a brand new site with it using a tool called Create React App. This tool sets everything up for you, so you can focus on building your website.

Understanding these basics will help you get comfortable with React and prepare you for creating fun, interactive web pages. Next we will use NPM, a javascript package manager to start building our Reciple Sharing application

Introduction to NPM

What is NPM?

NPM stands for Node Package Manager. It is a package manager for JavaScript, and is the default way to manage packages in the Node.js runtime environment. It helps you install, update, and manage libraries and dependencies in your projects efficiently.

Why Use NPM?

NPM makes it easy to share code with other developers, manage versions of dependencies, and ensure compatibility between different packages. It hosts thousands of free packages to download and use.

Installing NPM

NPM is distributed with Node.js, which means that when you download Node.js, you automatically get npm installed on your computer. Download Node.js (and npm) from nodejs.org.

Check Installation

To verify that you have Node.js and npm installed, you can run the following commands in your command prompt or terminal:

node -v
npm -v

This will output the versions of Node.js and npm installed on your system, indicating successful installation.

Basic Commands in NPM

Here are a few basic commands you'll frequently use in npm:

  • npm init: Initializes a new project and creates a package.json file.
  • npm install [package_name]: Installs a package and adds it to the package.json file.
  • npm start: Runs the script designated as the 'start' script in your package.json file.
  • npm test: Runs the script designated as the 'test' script in your package.json file.

Creating Your First Project

To create a new React application that will be the starting point for our recipe-sharing app, you use the create-react-app command. This is a tool maintained by Facebook that sets up a new React project with good defaults.

Create React App

npx create-react-app recipe-sharing-app

This command creates a new folder called recipe-sharing-app containing all the necessary setup, including a version of npm to manage the project's dependencies.

Navigate and Start

cd recipe-sharing-app
npm start

Running npm start will start the development server and open up your new React application in the default web browser.

NPM Dependency Errors

Due to dependency issues, running npm start might lead to an error that looks like this:

Cannot find module 'ajv/dist/compile/codegen'
Require stack:
- /Users/user/Desktop/recipe-sharing-app/node_modules/ajv-keywords/dist/definitions/typeof.js
- /Users/user/Desktop/recipe-sharing-app/node_modules/ajv-keywords/dist/keywords/typeof.js
- /Users/user/Desktop/recipe-sharing-app/node_modules/ajv-keywords/dist/keywords/index.js
- /Users/user/Desktop/recipe-sharing-app/node_modules/ajv-keywords/dist/index.js
- /Users/user/Desktop/recipe-sharing-app/node_modules/schema-utils/dist/validate.js
- /Users/user/Desktop/recipe-sharing-app/node_modules/schema-utils/dist/index.js
- /Users/user/Desktop/recipe-sharing-app/node_modules/webpack-dev-server/lib/Server.js
- /Users/user/Desktop/recipe-sharing-app/node_modules/react-scripts/scripts/start.js

Errors that start with 'Cannot find module' are dependency issues. Dependencies are packages written by other people that we use in our project. To use these these dependencies, we install them using npm install. For this particular error, the dependency is ajv. We can solve this error by running command:

npm install ajv

Now start the application by running command:

npm start

This initial setup provided by create-react-app includes a sample React application which you can now begin to modify as you progress through building your recipe-sharing application. You should see the image below:

Key Files and Directories

package.json

This is a crucial file in any Node.js and React project. It holds metadata relevant to the project and it is used for managing the project's dependencies, scripts, and versions.

  • Dependencies: Libraries your project requires, including React itself.
  • Scripts: Commands you can run from the command line, such as start, build, and test.
  • Version: The current version of your project.

Example snippet from package.json:

{
  "name": "recipe-sharing-app",
  "version": "1.0.0",
  "private": true,
  "dependencies": {
    "react": "^17.0.2",
    "react-dom": "^17.0.2",
    "react-scripts": "4.0.3"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  }
}

public/index.html

The single HTML file in your project where your React application is mounted. React will manage everything inside the <div id="root"></div>.

src/index.js

The entry point for your React application. This file typically sets up the React DOM rendering process and wraps the app component in any providers if you are using Redux or Context API.

src/App.js

This is a component file and serves as the root component of your React application. Most of your app’s primary components will be nested within App.js.

Example snippet from App.js:

import logo from './logo.svg';
import './App.css';

function App() {
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Edit <code>src/App.js</code> and save to reload.
        </p>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React
        </a>
      </header>
    </div>
  );
}

export default App;

src/App.css

This file contains the CSS for your App.js component. You can define styles specific to this component here.

node_modules/

This directory contains all the packages and their dependencies that npm has installed for your project. It is auto-generated when you run npm install.

.gitignore

This file specifies intentionally untracked files that Git should ignore. Files and directories like node_modules are typically listed here.

Additional Configuration Files

  • .eslintcache: Stores the linting information for quicker lint checks.
  • README.md: Usually contains information about the project, setup instructions, and other useful documentation.
  • package-lock.json or yarn.lock: These files lock down the versions of installed packages to ensure consistent installs across environments.

Understanding these files will help you better navigate and manage your React project as you build and expand your recipe-sharing application. Next, we'll explore more about React itself and how it functions within this structure. Let me know if you're ready to proceed or have any specific questions!

JSX: Syntax and Concepts

What is JSX?

JSX stands for JavaScript XML. It allows us to write our user interface in a way that looks similar to HTML but actually works inside JavaScript. This means you can write HTML-like code in your JavaScript files.

Key Features of JSX

It Looks Like HTML

JSX allows you to write HTML tags in your JavaScript files. This makes it easy to visualize the component layout directly in the code.

const element = <h1>Welcome to our Recipe App</h1>;
JSX is Stricter Than HTML

While JSX looks like HTML, it comes with a few rules that make it stricter:

  • className instead of class: In HTML, you use class to add CSS classes to elements. JSX uses className because class is a reserved word in JavaScript.

    const element = <div className="menu">...</div>;
    
  • htmlFor instead of for: Similarly, instead of for in <label> elements, JSX uses htmlFor since for is also reserved in JavaScript.

    const element = <label htmlFor="name">Name:</label>;
    
  • Closed tags: In JSX, every element must be closed. Even self-closing elements like <img>, <input>, and <br> must explicitly close in JSX.

    const element = <img src="logo.png" alt="Logo" />;
    
Embedding JavaScript in JSX

You can embed JavaScript expressions inside JSX by wrapping them in curly braces . This is useful for dynamically updating your UI based on certain conditions or variables.

const user = 'Alice';
const element = <h1>Hello, {user}</h1>;
Attributes and Nesting
  • Attributes: JSX elements can have attributes just like HTML elements. These include styles, classes, or custom attributes.

    const element = <a href="https://example.com" target="_blank">Visit Example</a>;
    
  • Nesting: You can nest JSX elements inside each other to create complex layouts.

    const element = (
    <div>
      <h1>Welcome to our Recipe App</h1>
      <p>Here you can find the best recipes!</p>
    </div>
    );
    
Using Loops in JSX

To render multiple elements based on a collection of data, you can use JavaScript array methods like .map() directly in JSX. This is particularly useful for displaying lists or tables where each item should be transformed into a JSX element.

const ingredients = ["Flour", "Sugar", "Butter", "Eggs"];
const ingredientList = (
  <ul>
    {ingredients.map((ingredient, index) => <li key={index}>{ingredient}</li>)}
  </ul>
);

In this example, .map() is used to iterate over the ingredients array, and for each item, a <li> element is generated. The key prop is crucial for helping React identify which items have changed, added, or removed, which optimizes performance during updates.

Using JSX in our Recipe Project App.js

After understanding the basics of JSX, let's use it in our project. Start by updating App.js with a basic structure:

import React from 'react';

function App() {
  return (
    <div>
      <h1>Welcome to the Recipe App</h1>
      <p>Explore a world of delicious recipes!</p>
    </div>
  );
}

export default App;

Run npm start to see this update in your web browser, you should see the output below:

React Components and Props

Components are the building blocks of any React application. They help you organize the user interface into reusable pieces. Think of them like custom, reusable HTML elements, but with superpowers.

Understanding Components

  • Reusability and Composition

Components can be reused throughout the application, which helps keep your code DRY (Don't Repeat Yourself). You can also compose larger components from smaller ones.

  • Isolation

Each component is isolated, meaning it operates independently. This makes debugging and testing easier because you can focus on one piece at a time.

  • Importing and Using Components

In React, you can create components in separate files and import them into other components to assemble your application. This modularity is one of React's core features, allowing for clean and organized code.

What are Props?

Props (short for "properties") are how components talk to each other. They let you pass data from parent components to child components. It's like giving parameters to a function.

Using Componenets and Props in Our Recipe Project

To demonstrate, we will build three components, RecipeDetails, RecipeIngredients and RecipeSteps. These will be used to demonstrate how components and props are used in REACT.

  1. RecipeDetails Component: This component shows a recipe's title and description and uses other components to list ingredients and preparation steps. We store the recipeTitle, recipeDescription, recipeIngredients and recipeSteps as values. We will then import the RecipeIngredients and RecipeSteps components and pass down the recipeIngredients and recipeSteps as props. Inside the src folder, make a RecipeDetails.js file and put the following code in.
import React from 'react';
import RecipeIngredients from './RecipeIngredients';
import RecipeSteps from './RecipeSteps';

function RecipeDetails() {
  const recipeTitle = "Chocolate Cake";
  const recipeDescription = "Delicious deep chocolate cake perfect for celebrations.";
  const recipeIngredients = ["2 cups sugar", "1-3/4 cups flour", "3/4 cup cocoa"];
  const recipeSteps = ["Preheat oven to 350°F", "Mix dry ingredients", "Bake for 30-35 minutes"];

  return (
    <div>
      <h1>{recipeTitle}</h1>
      <p>{recipeDescription}</p>
      <RecipeIngredients ingredients={recipeIngredients} />
      <RecipeSteps steps={recipeSteps} />
    </div>
  );
}

export default RecipeDetails;
  1. RecipeIngredients Component: Receives ingredients via props and then use the .map() method to display them. Inside the src folder, make a RecipeIngredients.js file and put the following code in.
import React from 'react';

function RecipeIngredients({ ingredients }) {
  return (
    <div>
      <h2>Ingredients</h2>
      <ul>
        {ingredients.map((ingredient) => (
          <li>{ingredient}</li>
        ))}
      </ul>
    </div>
  );
}

export default RecipeIngredients;
  1. RecipeSteps Component: Receives steps via props and then use the .map() method to display them. Inside the src folder, make a RecipeSteps.js file and put the following code in.
import React from 'react';

function RecipeSteps({ steps }) {
  return (
    <div>
      <h2>Preparation Steps</h2>
      <ul>
        {steps.map((step) => (
          <li>{step}</li>
        ))}
      </ul>
    </div>
  );
}

export default RecipeSteps;
  1. Integrating Components into App.js: Finally, to get the components showing on our browser, we have to add RecipeDetails to App.js.
import React from 'react';
import RecipeDetails from './RecipeDetails';

function App() {
  return (
    <div>
      <RecipeDetails />
    </div>
  );
}

export default App;

Run npm start to see how your components work together to display the recipe. It should look like the image below

These examples show how JSX and React components work together to build interactive web applications.

React State Management with useState

What is State Management?

In React, "state" refers to the data or attributes that can change over time within a component. Think of it like the memory of your component that can remember things and change them when needed. State management is how we handle these changes in a systematic way, ensuring the application behaves as expected.

Why Not Just Use Variables?

You might wonder why we can't just use regular variables instead of state in React. Here's why:

  • Persistence: Regular variables in React functions get reset every time the component updates. State, on the other hand, persists between re-renders.
  • Reactivity: State changes trigger React to update the user interface automatically. If you change a plain variable, React won't know about it and won't update the screen.

Introduction to useState

useState is a Hook that lets you add React state to function components. Hooks are functions that let you “hook into” React features from function components.

Using useState

Here's how you use useState:

import React, { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

In this example:

  • useState(0) initializes the state variable count with a value of 0.
  • setCount is a function that updates count.
  • When the button is clicked, setCount is called to increase the count by 1.

Applying useState in Our Recipe Project

We'll update the RecipeDetails component to use useState for managing recipeTitle, recipeDescription, recipeIngredients, and recipeSteps. This way, our component can dynamically update these values if needed.

Here's the updated RecipeDetails component using useState:

import React, { useState } from 'react'; //here we import useState into the project
import RecipeIngredients from './RecipeIngredients';
import RecipeSteps from './RecipeSteps';

function RecipeDetails() {
  const [recipeTitle, setRecipeTitle] = useState("Chocolate Cake");
  const [recipeDescription, setRecipeDescription] = useState("Delicious deep chocolate cake perfect for celebrations.");
  const [recipeIngredients, setRecipeIngredients] = useState(["2 cups sugar", "1-3/4 cups flour", "3/4 cup cocoa"]);
  const [recipeSteps, setRecipeSteps] = useState(["Preheat oven to 350°F", "Mix dry ingredients", "Bake for 30-35 minutes"]);

  return (
    <div>
      <h1>{recipeTitle}</h1>
      <p>{recipeDescription}</p>
      <RecipeIngredients ingredients={recipeIngredients} />
      <RecipeSteps steps={recipeSteps} />
    </div>
  );
}

export default RecipeDetails;

How This Improves Our Component

  • This change does not do much for the look of of page, but it ensures that recipeTitle, recipeDescription, recipeIngredients, and recipeSteps will be updated on the UI when they are changed, just like the counter example. The importance of this will be illustrated in further lectures.

Run npm start to see the new change. It should look like the image below

Handling Events in React

In React, handling user interactions such as clicks, form submissions, and mouse movements is done using events, similar to handling events on DOM elements in plain JavaScript. However, there are a few React-specific behaviors and syntax to consider.

How to Handle Events

React events are named using camelCase rather than lowercase. You pass a function as the event handler rather than a string.

Example: A Button Click Counter

Here's a simple example of a button that increments a counter when clicked:

import React, { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0);

  function handleIncrement() {
    setCount(count + 1);
  }

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={handleIncrement}>
        Click me
      </button>
    </div>
  );
}

export default Counter;

In this example:

  • setCount is a function provided by the useState hook that updates the state variable count.
  • onClick is an event property that React provides to listen for click events on the button and calls handleIncrement
  • The function handleIncrementis directly attached to onClick. It calls setCount, passing the new state value which is the current count plus one.

Conditional Rendering in React

Conditional rendering in React lets you display content based on certain conditions. It's like using conditional statements in JavaScript to decide what to display.

Using the Ternary Operator for Conditional Rendering

The ternary operator is a concise way to write an if-else statement. It's written as condition ? trueExpression : falseExpression.

Example: Displaying a Message Based on User Login State

Here's a simple example to display different messages based on whether a user is logged in:

import React, { useState } from 'react';

function UserGreeting() {
  const [isLoggedIn, setIsLoggedIn] = useState(false);

  return (
    <div>
      {isLoggedIn ? <p>Welcome back!</p> : <p>Please sign in.</p>}
    </div>
  );
}

export default UserGreeting;

In this example:

  • isLoggedIn is a boolean state that tracks if the user is logged in.
  • The ternary operator checks isLoggedIn. If true, it displays "Welcome back!", otherwise, it shows "Please sign in."

Applying Event Handlers and Conditional Rendering to our Recipe Project

Let's update the RecipeDetails component to include buttons for toggling the display of ingredients and steps using conditional rendering.

import React, { useState } from 'react';
import RecipeIngredients from './RecipeIngredients';
import RecipeSteps from './RecipeSteps';

function RecipeDetails() {
  const [recipeTitle] = useState("Chocolate Cake");
  const [recipeDescription] = useState("Delicious deep chocolate cake perfect for celebrations.");
  const [recipeIngredients] = useState(["2 cups sugar", "1-3/4 cups flour", "3/4 cup cocoa"]);
  const [recipeSteps] = useState(["Preheat oven to 350°F", "Mix dry ingredients", "Bake for 30-35 minutes"]);
  const [showIngredients, setShowIngredients] = useState(true);
  const [showSteps, setShowSteps] = useState(true);

  return (
    <div>
      <h1>{recipeTitle}</h1>
      <p>{recipeDescription}</p>
      <button onClick={() => setShowIngredients(!showIngredients)}>
        {showIngredients ? 'Hide Ingredients' : 'Show Ingredients'}
      </button>
      {showIngredients && <RecipeIngredients ingredients={recipeIngredients} />}
      <button onClick={() => setShowSteps(!showSteps)}>
        {showSteps ? 'Hide Steps' : 'Show Steps'}
      </button>
      {showSteps && <RecipeSteps steps={recipeSteps} />}
    </div>
  );
}

export default RecipeDetails;

Explanation of the Updated RecipeDetails Component:

  • showIngredients and showSteps are state variables initialized to true. They determine whether the ingredients and steps are shown.
  • Each button toggles its corresponding state between true and false when clicked, using the setShowIngredients and setShowSteps functions.
  • The ternary operator within the button text changes the button label based on the state (showIngredients or showSteps).
  • The {showIngredients && <RecipeIngredients ingredients={recipeIngredients} />} syntax means "if showIngredients is true, then render the RecipeIngredients component". This is an example of conditional rendering using logical AND.

These additions make the RecipeDetails component interactive, allowing users to control what information is displayed. Run npm start and you should see the image below: Clicking on the buttons toggle the display of the recipe ingredients and recipe steps

Styling React Components with CSS Files

Styling React components using CSS files is one of the most common and straightforward methods. It involves creating separate CSS files for your components and linking them in your React components, similar to how you would style a traditional HTML page.

Why Use CSS Files?

  1. Familiarity: Most web developers are already comfortable with CSS.
  2. Separation of Concerns: Keeping your CSS separate from your JavaScript code helps maintain cleaner and more organized code.
  3. Performance: CSS files can be cached by the browser, which can lead to performance improvements.

How to Style Components with CSS Files

Step 1: Create a CSS File

Create a new CSS file for your component. For example, if you have a component named App.js, you might create a corresponding CSS file named App.css.

Step 2: Write Your Styles

Add the CSS rules you want to apply to your component in the CSS file you created. For instance:

/* App.css */
.App {
    text-align: center;
    color: darkslategray;
}

Step 3: Import CSS File in Your Component

In your React component file, import the CSS file using a relative path. This tells your component which styles to use.

// App.js
import React from 'react';
import './App.css';  // Importing the CSS file

function App() {
    return <div className="App">Hello, World!</div>;
}

This will apply the styles defined in App.css to the App component.

Styling the Components in our Recipe Project

Now, let's apply CSS to the RecipeDetails, RecipeIngredients, and RecipeSteps components in your project.

  • Create a RecipeDetails.css file
/* RecipeDetails.css */
.recipeDetails {
    font-family: Arial, sans-serif;
    margin: 20px;
    padding: 20px;
    border: 1px solid #ccc;
    border-radius: 8px;
}

.recipeTitle {
    color: #333;
    font-size: 24px;
}

.recipeDescription {
    color: #666;
    font-size: 16px;
}

.toggleButton {
    padding: 10px 20px;
    margin: 10px;
    background-color: lightgray;
    border: none;
    border-radius: 4px;
    cursor: pointer;
}
  • Update the RecipeDetails.js file to use classNames and import RecipeDetails.css.
import React, { useState } from 'react';
import './RecipeDetails.css'; // Importing the CSS styles
import RecipeIngredients from './RecipeIngredients';
import RecipeSteps from './RecipeSteps';

function RecipeDetails() {
    const [recipeTitle] = useState("Chocolate Cake");
    const [recipeDescription] = useState("Delicious deep chocolate cake perfect for celebrations.");
    const [recipeIngredients] = useState([
        "2 cups sugar", 
        "1-3/4 cups flour", 
        "3/4 cup cocoa"
    ]);
    const [recipeSteps] = useState([
        "Preheat oven to 350°F", 
        "Mix dry ingredients", 
        "Bake for 30-35 minutes"
    ]);
    const [showIngredients, setShowIngredients] = useState(true);
    const [showSteps, setShowSteps] = useState(true);

    return (
        <div className="recipeDetails">
            <h1 className="recipeTitle">{recipeTitle}</h1>
            <p className="recipeDescription">{recipeDescription}</p>
            <button className="toggleButton" onClick={() => setShowIngredients(!showIngredients)}>
                {showIngredients ? 'Hide Ingredients' : 'Show Ingredients'}
            </button>
            {showIngredients && <RecipeIngredients ingredients={recipeIngredients} />}
            <button className="toggleButton" onClick={() => setShowSteps(!showSteps)}>
                {showSteps ? 'Hide Steps' : 'Show Steps'}
            </button>
            {showSteps && <RecipeSteps steps={recipeSteps} />}
        </div>
    );
}

export default RecipeDetails;
  • Create a RecipeSteps.css file
/* RecipeSteps.css */
.stepsList {
    list-style: none;
    padding: 0;
    margin-top: 20px;
}

.stepsList li {
    padding: 10px;
    margin-bottom: 5px;
    background-color: #f9f9f9;
    border-left: 5px solid green;
}
  • Update the RecipeSteps.js file to use classNames and import RecipeSteps.css.
import React from 'react';
import './RecipeSteps.css'; // Importing the CSS styles

function RecipeSteps({ steps }) {
    return (
        <div>
            <h2>Preparation Steps</h2>
            <ul className="stepsList">
                {steps.map((step, index) => (
                    <li key={index}>{step}</li>
                ))}
            </ul>
        </div>
    );
}

export default RecipeSteps;
  • Create a RecipeIngredients.css file
/* RecipeIngredients.css */
.ingredientsList {
    list-style-type: none;
    padding: 0;
}

.ingredientsList li {
    padding: 5px 0;
    border-bottom: 1px solid #eee;
}

.ingredientsList li:last-child {
    border-bottom: none;
}
  • Update the RecipeIngredients.js file to use classNames and import RecipeIngredients.css.
import React from 'react';
import './RecipeIngredients.css';

function RecipeIngredients({ ingredients }) {
    return (
        <div>
            <h2>Ingredients</h2>
            <ul className="ingredientsList">
                {ingredients.map((ingredient, index) => (
                    <li key={index}>{ingredient}</li>
                ))}
            </ul>
        </div>
    );
}

export default RecipeIngredients;

By following these steps, you effectively separate the concerns of styling and functionality, keeping your project organized and maintainable. Run your project with the command npm start, you should see the image below: