In this article, we’ll delve into how to implement filtering in a MERN (MongoDB, Express.js, React, Node.js) stack application. We’ll cover everything from setting up the project to implementing a complete CRUD interface with GUI design, error handling, and form validation. This guide is designed to provide a detailed, step-by-step approach with commented code examples to ensure you can follow along and implement these features in your own projects.
Introduction
The MERN stack is a popular choice for building modern web applications. It combines the flexibility and power of MongoDB, Express.js, React, and Node.js. In this guide, we’ll build a simple book management application that allows users to filter books by genre. We’ll cover backend setup with Express.js, frontend implementation with React, and styling with CSS.
Setting Up the Project
Step 1: Initialize the Project
First, create a new directory for your project and initialize a new Node.js application.
mkdir mern-filtering-app
cd mern-filtering-app
npm init -y
Code Explanation
Let’s break down the code:
mkdir mern-filtering-app
Create the Project Directory:
- Purpose: This command creates a new directory named
mern-filtering-app
. - Function: The
mkdir
command stands for “make directory,” and it is used to create a new directory in the file system. - Usage: By running this command, you are creating a container for your new project. This directory will hold all the files and subdirectories related to your MERN stack application.
cd mern-filtering-app
Change to the Project Directory:
- Purpose: This command changes the current working directory to the newly created
mern-filtering-app
directory. - Function: The
cd
command stands for “change directory,” and it is used to navigate into a specified directory. - Usage: By running this command, you are moving into the
mern-filtering-app
directory, where you will set up and manage your project files.
npm init -y
Initialize the Node.js Project:
- Purpose: This command initializes a new Node.js project in the current directory by creating a
package.json
file. - Function: The
npm init
command is used to create apackage.json
file, which is essential for managing the dependencies and scripts for your Node.js project. - Usage: The
-y
flag automatically answers “yes” to all the prompts thatnpm init
would typically ask (such as project name, version, description, etc.), thereby creating thepackage.json
file with default settings.
Next, install the necessary dependencies.
npm install express mongoose cors body-parser
npx create-react-app client
Code Explanation
Let’s break down the code:
npm install express mongoose cors body-parser
Command: npm install express mongoose cors body-parser
- Purpose: This command installs the specified Node.js packages (
express
,mongoose
,cors
, andbody-parser
) as dependencies in your project. - Function: The
npm install
command is used to install Node.js packages, and the names listed after the command are the packages to be installed. - Usage: By running this command, you are adding essential libraries to your project, each serving a specific purpose.
express
:- Purpose: Express is a web application framework for Node.js.
- Function: It provides a robust set of features to develop web and mobile applications, including routing, middleware, and more.
- Usage: It simplifies the creation of server-side logic and handling HTTP requests and responses.
mongoose
:- Purpose: Mongoose is an Object Data Modeling (ODM) library for MongoDB and Node.js.
- Function: It provides a straightforward, schema-based solution to model application data. It includes built-in type casting, validation, query building, and business logic hooks.
- Usage: It helps manage relationships between data, provides schema validation, and translates between objects in code and the representation of those objects in MongoDB.
cors
:- Purpose: CORS (Cross-Origin Resource Sharing) is a middleware package for Express.
- Function: It allows or restricts requested resources on a web server depending on where the HTTP request was initiated. It helps in enabling cross-origin requests in the Express application.
- Usage: It is used to configure the server to allow requests from different origins, which is essential for web applications that make requests to an API server from a different domain.
body-parser
:- Purpose: Body-parser is a middleware for parsing incoming request bodies in a middleware before your handlers.
- Function: It parses the JSON, buffer, string, and URL-encoded data submitted in HTTP requests.
- Usage: It helps in parsing the body of incoming requests and making the data available under
req.body
.
npx create-react-app client
create-react-app
:- Purpose: It is a tool that sets up a new React project with a sensible default configuration.
- Function: It configures the React application with a webpack, Babel, and a development server, so you can start building your React app immediately without dealing with configuration.
- Usage: It creates a new directory with a pre-configured React application, including essential files and folder structures.
Bringing It All Together
By running these commands, you will have set up both the backend (with Express.js, Mongoose, CORS, and body-parser) and the frontend (with React) of your MERN stack application. The backend will handle data storage and API routes, while the frontend will provide the user interface for interacting with the application.
Step 2: Backend Setup (Express.js)
Creating the Server
Create a file named server.js
and set up your Express server.
// server.js
const express = require('express');
const mongoose = require('mongoose');
const cors = require('cors');
const bodyParser = require('body-parser');
// Initialize Express
const app = express();
// Middleware
app.use(cors());
app.use(bodyParser.json());
// Connect to MongoDB
mongoose.connect('mongodb://localhost:27017/mern_filtering', {
useNewUrlParser: true,
useUnifiedTopology: true
}).then(() => console.log('MongoDB connected'))
.catch(err => console.error(err));
// Book Schema
const bookSchema = new mongoose.Schema({
title: String,
genre: String
});
const Book = mongoose.model('Book', bookSchema);
// Routes
app.get('/api/books', async (req, res) => {
try {
const genre = req.query.genre;
const books = genre ? await Book.find({ genre }) : await Book.find();
res.json(books);
} catch (err) {
res.status(500).json({ error: err.message });
}
});
app.post('/api/books', async (req, res) => {
try {
const { title, genre } = req.body;
const newBook = new Book({ title, genre });
await newBook.save();
res.status(201).json(newBook);
} catch (err) {
res.status(400).json({ error: err.message });
}
});
// Start the server
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
Let’s break down and explain each part of the server.js
file:
// server.js
// Import necessary modules
const express = require('express');
const mongoose = require('mongoose');
const cors = require('cors');
const bodyParser = require('body-parser');
// Initialize Express
const app = express();
Explanation
Modules Import:
express
: A web application framework for Node.js.mongoose
: An Object Data Modeling (ODM) library for MongoDB and Node.js, used for database operations.cors
: Middleware to enable Cross-Origin Resource Sharing, allowing your API to be accessed from different origins.body-parser
: Middleware to parse incoming request bodies in a middleware before your handlers, available underreq.body
.Initialize Express:
const app = express();
: Initializes a new Express application.
// Middleware
app.use(cors());
app.use(bodyParser.json());
Explanation
- Middleware:
app.use(cors());
: Enables CORS for all routes, allowing your API to be accessible from different domains.app.use(bodyParser.json());
: Configures the app to usebody-parser
middleware, which parses incoming request bodies as JSON.
// Connect to MongoDB
mongoose.connect('mongodb://localhost:27017/mern_filtering').then(() => console.log('MongoDB connected'))
.catch(err => console.error(err));
Explanation
- Connect to MongoDB:
mongoose.connect(...)
: Connects to a MongoDB database namedmern_filtering
running onlocalhost
and port27017
..then(() => console.log('MongoDB connected'))
: Logs a message to the console if the connection is successful..catch(err => console.error(err))
: Logs an error message to the console if the connection fails.
// Book Schema
const bookSchema = new mongoose.Schema({
title: String,
genre: String
});
const Book = mongoose.model('Book', bookSchema);
Explanation
- Book Schema:
const bookSchema = new mongoose.Schema(...)
: Defines a new Mongoose schema for books, withtitle
andgenre
fields, both of typeString
.const Book = mongoose.model('Book', bookSchema);
: Creates a Mongoose model namedBook
based on the defined schema. This model will be used to interact with thebooks
collection in the database.
// Routes
app.get('/api/books', async (req, res) => {
try {
const genre = req.query.genre;
const books = genre ? await Book.find({ genre }) : await Book.find();
res.json(books);
} catch (err) {
res.status(500).json({ error: err.message });
}
});
app.post('/api/books', async (req, res) => {
try {
const { title, genre } = req.body;
const newBook = new Book({ title, genre });
await newBook.save();
res.status(201).json(newBook);
} catch (err) {
res.status(400).json({ error: err.message });
}
});
Explanation
GET
/api/books
Route:app.get('/api/books', async (req, res) => {...})
: Defines a route to get all books or filter them by genre.const genre = req.query.genre;
: Gets thegenre
query parameter from the request.const books = genre ? await Book.find({ genre }) : await Book.find();
: If a genre is specified, finds books matching the genre. Otherwise, returns all books.res.json(books);
: Sends the found books as a JSON response.catch (err) {...}
: Handles errors by sending a 500 status code and error message.
POST
/api/books
Route:app.post('/api/books', async (req, res) => {...})
: Defines a route to add a new book.const { title, genre } = req.body;
: Extractstitle
andgenre
from the request body.const newBook = new Book({ title, genre });
: Creates a new book instance with the given title and genre.await newBook.save();
: Saves the new book to the database.res.status(201).json(newBook);
: Sends the saved book as a JSON response with a 201 status code (Created).catch (err) {...}
: Handles errors by sending a 400 status code and error message.
// Start the server
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
Explanation
- Start the Server:
const PORT = process.env.PORT || 5000;
: Sets the port to the value from the environment variablePORT
or defaults to5000
.app.listen(PORT, () => {...})
: Starts the Express server on the specified port.console.log(
Server running on port ${PORT});
: Logs a message indicating the server is running and the port number.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut elit tellus, luctus nec ullamcorper mattis, pulvinar dapibus leo.
Defining the Book Model
Create a models
directory and add a file Book.js
.
// models/Book.js
const mongoose = require('mongoose');
const bookSchema = new mongoose.Schema({
title: String,
genre: String
});
module.exports = mongoose.model('Book', bookSchema);
Frontend Setup
Step 1: Create React App
Navigate back to the project root directory and create a new React app inside a client
folder.
npx create-react-app client
Command Explanation: npx create-react-app client
The command npx create-react-app client
is used to set up a new React application with a pre-configured development environment. Let’s break down each part of this command to understand what it does and why it is useful.
npx
- Purpose:
npx
is a package runner tool that comes with npm (version 5.2.0 and higher). - Function: It allows you to execute npm packages without needing to install them globally.
- Usage: You can use
npx
to run packages that you do not want to install globally on your machine. It fetches the package from the npm registry, runs it, and then removes it.
create-react-app
- Purpose:
create-react-app
is a command-line tool that sets up a new React project with a sensible default configuration. - Function: It creates a new React application with a standardized project structure, pre-configured with tools like Webpack, Babel, and a development server.
- Usage: It simplifies the process of setting up a new React project by taking care of the configuration details, so developers can focus on writing code rather than setting up build tools.
client
- Purpose: This specifies the directory name where the new React application will be created.
- Function:
create-react-app
will create a new directory namedclient
and initialize the React project inside it. - Usage: This name can be any valid directory name, and it will become the root directory of your new React project.
Step 2: Install Axios
Navigate to the client
directory and install Axios for making HTTP requests.
cd client
npm install axios
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut elit tellus, luctus nec ullamcorper mattis, pulvinar dapibus leo.
Command: cd client
- Purpose: This command changes the current working directory to the
client
directory. - Function: The
cd
command stands for “change directory.” It allows you to navigate into a specified directory in your file system. - Usage: By running
cd client
, you are moving into theclient
directory that was created bycreate-react-app
. This directory contains all the files and configuration for your React application.
When you create a React application using create-react-app
, it creates a new directory with the name you specified (in this case, client
). This directory contains all the files and configuration needed for your React project, including:
node_modules/
: Contains all the installed npm packages.public/
: Contains static assets likeindex.html
.src/
: Contains the source code for your React application, including components, styles, and tests.package.json
: Configuration file for npm, listing dependencies and scripts.
By changing the directory to client
, you ensure that subsequent commands (such as installing dependencies or starting the development server) are executed within the context of your React project.
Command: npm install axios
- Purpose: This command installs the
axios
package as a dependency in your React project. - Function: The
npm install
command is used to install Node.js packages.axios
is a promise-based HTTP client for the browser and Node.js. - Usage: By running this command, you add
axios
to your project, which you can use to make HTTP requests to your backend server or any other API.
axios
is a popular library used to make HTTP requests from the browser or Node.js. It simplifies the process of making requests and handling responses.
- Why use
axios
?- Promise-based: Makes it easier to work with asynchronous requests using promises or async/await syntax.
- Browser Compatibility: Works in the browser and Node.js environments.
- Interceptors: Allows you to intercept requests or responses before they are handled by then or catch.
- Cancellation: Supports request cancellation.
- CSRF Protection: Supports cross-site request forgery (CSRF) protection.
By installing axios
, you can use it in your React components to communicate with your backend server (built with Express.js) or any external APIs. This is essential for fetching and submitting data in your application.
Step 3: Create Components
Create a components
directory inside the src
folder and add the following files: BookList.js
, BookForm.js
.
BookList.js
// src/components/BookList.js
import React, { useState, useEffect } from 'react';
import axios from 'axios';
const BookList = () => {
const [books, setBooks] = useState([]);
const [genreFilter, setGenreFilter] = useState('');
useEffect(() => {
fetchBooks();
}, [genreFilter]);
const fetchBooks = async () => {
try {
const response = await axios.get('/api/books', {
params: { genre: genreFilter }
});
setBooks(response.data);
} catch (error) {
console.error('Error fetching books:', error);
}
};
const handleFilterChange = (e) => {
setGenreFilter(e.target.value);
};
return (
<div>
<h2>Book List</h2>
<div>
<label htmlFor="genreFilter">Filter by Genre: </label>
<select id="genreFilter" value={genreFilter} onChange={handleFilterChange}>
<option value="">All Genres</option>
<option value="Fiction">Fiction</option>
<option value="Non-fiction">Non-fiction</option>
</select>
</div>
<ul>
{books.map((book) => (
<li key={book._id}>{book.title}</li>
))}
</ul>
</div>
);
};
export default BookList;
This code defines a React component named BookList
that fetches and displays a list of books from a backend server. It also includes a dropdown to filter books by genre. Let’s break down the code step-by-step:
import React, { useState, useEffect } from 'react';
import axios from 'axios';
React
: The core library for building user interfaces.useState
: A React hook that lets you add state to functional components.useEffect
: A React hook that lets you perform side effects in functional components (like fetching data from an API).axios
: A promise-based HTTP client for making requests to the backend server.
const BookList = () => {
const [books, setBooks] = useState([]);
const [genreFilter, setGenreFilter] = useState('');
Component Definition
BookList
: A functional component that manages the state and rendering of the book list.useState([])
: Initializes thebooks
state variable as an empty array.setBooks
is the function to update this state.useState('')
: Initializes thegenreFilter
state variable as an empty string.setGenreFilter
is the function to update this state.
useEffect(() => {
fetchBooks();
}, [genreFilter]);
useEffect Hook
useEffect
: A hook that runs thefetchBooks
function whenever thegenreFilter
state changes. This hook is responsible for fetching the data from the backend whenever the component mounts or the genre filter is updated.
const fetchBooks = async () => {
try {
const response = await axios.get('/api/books', {
params: { genre: genreFilter }
});
setBooks(response.data);
} catch (error) {
console.error('Error fetching books:', error);
}
};
fetchBooks Function
fetchBooks
: An asynchronous function that fetches books from the backend.axios.get('/api/books', { params: { genre: genreFilter } })
: Sends a GET request to the/api/books
endpoint with thegenre
query parameter.response.data
: The data returned from the server, which is the list of books.setBooks(response.data)
: Updates thebooks
state with the fetched data.catch (error)
: Catches and logs any errors that occur during the fetch operation.
const handleFilterChange = (e) => {
setGenreFilter(e.target.value);
};
handleFilterChange Function
handleFilterChange
: A function that updates thegenreFilter
state based on the user’s selection from the dropdown menu.e.target.value
: The value of the selected option in the dropdown menu.
return (
<div>
<h2>Book List</h2>
<div>
<label htmlFor="genreFilter">Filter by Genre: </label>
<select id="genreFilter" value={genreFilter} onChange={handleFilterChange}>
<option value="">All Genres</option>
<option value="Fiction">Fiction</option>
<option value="Non-fiction">Non-fiction</option>
</select>
</div>
<ul>
{books.map((book) => (
<li key={book._id}>{book.title}</li>
))}
</ul>
</div>
);
};
JSX Return
<div>
: The root container for the component.<h2>Book List</h2>
: A header for the book list.<label htmlFor="genreFilter">Filter by Genre: </label>
: A label for the dropdown menu.<select id="genreFilter" value={genreFilter} onChange={handleFilterChange}>
: A dropdown menu for selecting a genre. Thevalue
attribute is bound to thegenreFilter
state, andonChange
triggers thehandleFilterChange
function.<option value="">All Genres</option>
: An option to show all books.<option value="Fiction">Fiction</option>
: An option to filter books by the “Fiction” genre.<option value="Non-fiction">Non-fiction</option>
: An option to filter books by the “Non-fiction” genre.
<ul>
: A list that displays the books.{books.map((book) => (<li key={book._id}>{book.title}</li>))}
: Iterates over thebooks
array and renders each book as a list item. Thekey
attribute is set tobook._id
to provide a unique identifier for each list item.
export default BookList;
Export Component
export default BookList
: Exports theBookList
component as the default export of the module, making it available for import in other files.
Summary
- State Management: The component uses
useState
to manage thebooks
andgenreFilter
state. - Data Fetching: The
fetchBooks
function usesaxios
to fetch books from the backend, filtered by the selected genre. - Event Handling: The
handleFilterChange
function updates thegenreFilter
state when the user selects a different genre. - Rendering: The component renders a dropdown menu for genre selection and a list of books that are filtered based on the selected genre.
This BookList
component allows users to filter and view a list of books by genre, demonstrating the integration of React state management, lifecycle methods, and HTTP requests.
BookForm.js
// src/components/BookForm.js
import React, { useState } from 'react';
import axios from 'axios';
const BookForm = ({ onBookAdded }) => {
const [title, setTitle] = useState('');
const [genre, setGenre] = useState('');
const [error, setError] = useState('');
const handleSubmit = async (e) => {
e.preventDefault();
try {
const response = await axios.post('/api/books', { title, genre });
setTitle('');
setGenre('');
setError('');
onBookAdded(response.data);
} catch (error) {
setError('Failed to add book');
}
};
return (
<div>
<h2>Add a New Book</h2>
{error && <p style={{ color: 'red' }}>{error}</p>}
<form onSubmit={handleSubmit}>
<div>
<label htmlFor="title">Title: </label>
<input
type="text"
id="title"
value={title}
onChange={(e) => setTitle(e.target.value)}
required
/>
</div>
<div>
<label htmlFor="genre">Genre: </label>
<select id="genre" value={genre} onChange={(e) => setGenre(e.target.value)} required>
<option value="">Select Genre</option>
<option value="Fiction">Fiction</option>
<option value="Non-fiction">Non-fiction</option>
</select>
</div>
<button type="submit">Add Book</button>
</form>
</div>
);
};
export default BookForm;
This code defines a React component named BookForm
that provides a form for adding new books. Let’s break down the code step-by-step:
import React, { useState } from 'react';
import axios from 'axios';
Imports
React
: The core library for building user interfaces.useState
: A React hook that lets you add state to functional components.axios
: A promise-based HTTP client for making requests to the backend server.
const BookForm = ({ onBookAdded }) => {
const [title, setTitle] = useState('');
const [genre, setGenre] = useState('');
const [error, setError] = useState('');
Component Definition
BookForm
: A functional component that manages the state and rendering of the book form.- Props:
onBookAdded
: A function passed as a prop to handle the event when a new book is successfully added.
- State Variables:
useState('')
: Initializestitle
,genre
, anderror
state variables as empty strings. ThesetTitle
,setGenre
, andsetError
functions are used to update these states.
const handleSubmit = async (e) => {
e.preventDefault();
try {
const response = await axios.post('/api/books', { title, genre });
setTitle('');
setGenre('');
setError('');
onBookAdded(response.data);
} catch (error) {
setError('Failed to add book');
}
};
handleSubmit Function
handleSubmit
: An asynchronous function that handles the form submission.e.preventDefault()
: Prevents the default form submission behavior (which would reload the page).axios.post('/api/books', { title, genre })
: Sends a POST request to the/api/books
endpoint with the book’stitle
andgenre
.- Response Handling:
- On success: Clears the input fields by setting
title
andgenre
to empty strings, resetserror
to an empty string, and callsonBookAdded
with the new book data. - On failure: Sets the
error
state to ‘Failed to add book’.
- On success: Clears the input fields by setting
return (
<div>
<h2>Add a New Book</h2>
{error && <p style={{ color: 'red' }}>{error}</p>}
<form onSubmit={handleSubmit}>
<div>
<label htmlFor="title">Title: </label>
<input
type="text"
id="title"
value={title}
onChange={(e) => setTitle(e.target.value)}
required
/>
</div>
<div>
<label htmlFor="genre">Genre: </label>
<select id="genre" value={genre} onChange={(e) => setGenre(e.target.value)} required>
<option value="">Select Genre</option>
<option value="Fiction">Fiction</option>
<option value="Non-fiction">Non-fiction</option>
</select>
</div>
<button type="submit">Add Book</button>
</form>
</div>
);
};
JSX Return
- Container:
<div>
: The root container for the component.<h2>Add a New Book</h2>
: A header for the form.{error && <p style={{ color: 'red' }}>{error}</p>}
: Conditionally renders an error message in red if there is an error.
- Form:
<form onSubmit={handleSubmit}>
: A form element with anonSubmit
handler that triggers thehandleSubmit
function.
- Title Input:
<label htmlFor="title">Title: </label>
: A label for the title input field.<input type="text" id="title" value={title} onChange={(e) => setTitle(e.target.value)} required />
: A controlled input field for the book’s title. Thevalue
attribute is bound to thetitle
state, andonChange
updates the state.
- Genre Select:
<label htmlFor="genre">Genre: </label>
: A label for the genre select field.<select id="genre" value={genre} onChange={(e) => setGenre(e.target.value)} required>
: A controlled select field for the book’s genre. Thevalue
attribute is bound to thegenre
state, andonChange
updates the state.<option value="">Select Genre</option>
: A default option prompting the user to select a genre.<option value="Fiction">Fiction</option>
: An option for the “Fiction” genre.<option value="Non-fiction">Non-fiction</option>
: An option for the “Non-fiction” genre.
- Submit Button:
<button type="submit">Add Book</button>
: A button to submit the form.
export default BookForm;
Export Component
export default BookForm
: Exports theBookForm
component as the default export of the module, making it available for import in other files.
Summary
- State Management: The component uses
useState
to manage thetitle
,genre
, anderror
state. - Form Handling: The
handleSubmit
function handles form submission, sending a POST request to the backend to add a new book. - Event Handling: The input fields and select dropdown use
onChange
handlers to update the state. - Conditional Rendering: The error message is conditionally rendered based on the
error
state. - Rendering: The component renders a form with input fields for the book’s title and genre, and a submit button.
This BookForm
component provides a user-friendly interface for adding new books to the application, demonstrating the integration of React state management, form handling, and HTTP requests.
Step 4: Update App Component
Update the App.js
file to include the BookList
and BookForm
components.
// src/App.js
import React, { useState } from 'react';
import BookList from './components/BookList';
import BookForm from './components/BookForm';
import './App.css';
const App = () => {
const [books, setBooks] = useState([]);
const handleBookAdded = (newBook) => {
setBooks((prevBooks) => [...prevBooks, newBook]);
};
return (
<div className="App">
<h1>MERN Stack Filtering Application</h1>
<BookForm onBookAdded={handleBookAdded} />
<BookList books={books} />
</div>
);
};
export default App;
This code defines the main App
component of your React application. It integrates the BookForm
and BookList
components to create a complete user interface for adding and viewing books. Let’s break down the code step-by-step:
import React, { useState } from 'react';
import BookList from './components/BookList';
import BookForm from './components/BookForm';
import './App.css';
Imports
React
: The core library for building user interfaces.useState
: A React hook that lets you add state to functional components.BookList
: The component that displays a list of books, imported from thecomponents
directory.BookForm
: The component that provides a form for adding new books, imported from thecomponents
directory../App.css
: The CSS file that contains styling for theApp
component.
const App = () => {
const [books, setBooks] = useState([]);
Component Definition
App
: A functional component that manages the state and rendering of the main application.- State Variables:
useState([])
: Initializes thebooks
state variable as an empty array. ThesetBooks
function is used to update this state.
const handleBookAdded = (newBook) => {
setBooks((prevBooks) => [...prevBooks, newBook]);
};
handleBookAdded Function
handleBookAdded
: A function that handles the addition of a new book.- Parameters:
newBook
– The book object that has been added. - Functionality: Updates the
books
state by appending the new book to the existing array of books. TheprevBooks
argument represents the current state of thebooks
array, and[...prevBooks, newBook]
creates a new array with the new book added at the end.
- Parameters:
return (
<div className="App">
<h1>MERN Stack Filtering Application</h1>
<BookForm onBookAdded={handleBookAdded} />
<BookList books={books} />
</div>
);
};
JSX Return
- Container:
<div className="App">
: The root container for the component, with a class nameApp
for styling.<h1>MERN Stack Filtering Application</h1>
: A header for the application.
- Components:
<BookForm onBookAdded={handleBookAdded} />
: Renders theBookForm
component and passes thehandleBookAdded
function as a prop namedonBookAdded
. This allows theBookForm
to notify theApp
component when a new book is added.<BookList books={books} />
: Renders theBookList
component and passes thebooks
state as a prop namedbooks
. This allows theBookList
to display the current list of books.
export default App;
Export component
export default App
: Exports theApp
component as the default export of the module, making it available for import in other files.
Summary
- State Management: The
App
component usesuseState
to manage thebooks
state, which holds the list of books. - Event Handling: The
handleBookAdded
function updates thebooks
state when a new book is added. - Component Composition: The
App
component renders theBookForm
andBookList
components, passing necessary props to each. - Styling: The component uses a CSS class
App
for styling.
This App
component serves as the main entry point of your React application, integrating the form for adding new books and the list for displaying them. It demonstrates the use of React state management, event handling, and component composition to build a functional and interactive user interface.
Step 5: Add Styling
Create an App.css
file to style the components.
/* src/App.css */
.App {
text-align: center;
}
h1 {
color: #2c3e50;
}
form {
margin: 20px 0;
}
label {
margin-right: 10px;
}
input, select {
margin-bottom: 10px;
}
button {
background-color: #3498db;
color: white;
border: none;
padding: 10px 20px;
cursor: pointer;
}
button:hover {
background-color: #2980b9;
}
ul {
list-style-type: none;
padding: 0;
}
li {
margin: 5px 0;
}
Step 6: Run the Application
Navigate back to the project root directory and run both the backend and frontend servers.
# In one terminal window, run the backend server
node server.js
# In another terminal window, navigate to the client directory and start the React app
cd client
npm start
Links and Resources
Welcome to DevTechTutor.com, your ultimate resource for mastering web development and technology! Whether you're a beginner eager to dive into coding or an experienced developer looking to sharpen your skills, DevTechTutor.com is here to guide you every step of the way. Our mission is to make learning web development accessible, engaging, and effective.