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
mkdircommand 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-appdirectory. - Function: The
cdcommand 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-appdirectory, 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.jsonfile. - Function: The
npm initcommand is used to create apackage.jsonfile, which is essential for managing the dependencies and scripts for your Node.js project. - Usage: The
-yflag automatically answers “yes” to all the prompts thatnpm initwould typically ask (such as project name, version, description, etc.), thereby creating thepackage.jsonfile 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 installcommand 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-parsermiddleware, 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_filteringrunning onlocalhostand 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, withtitleandgenrefields, both of typeString.const Book = mongoose.model('Book', bookSchema);: Creates a Mongoose model namedBookbased on the defined schema. This model will be used to interact with thebookscollection 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/booksRoute: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 thegenrequery 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/booksRoute:app.post('/api/books', async (req, res) => {...}): Defines a route to add a new book.const { title, genre } = req.body;: Extractstitleandgenrefrom 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 variablePORTor 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:
npxis 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
npxto 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-appis 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-appwill create a new directory namedclientand 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
clientdirectory. - Function: The
cdcommand 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 theclientdirectory 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
axiospackage as a dependency in your React project. - Function: The
npm installcommand is used to install Node.js packages.axiosis a promise-based HTTP client for the browser and Node.js. - Usage: By running this command, you add
axiosto 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 thebooksstate variable as an empty array.setBooksis the function to update this state.useState(''): Initializes thegenreFilterstate variable as an empty string.setGenreFilteris the function to update this state.
useEffect(() => {
fetchBooks();
}, [genreFilter]);
useEffect Hook
useEffect: A hook that runs thefetchBooksfunction whenever thegenreFilterstate 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/booksendpoint with thegenrequery parameter.response.data: The data returned from the server, which is the list of books.setBooks(response.data): Updates thebooksstate 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 thegenreFilterstate 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. Thevalueattribute is bound to thegenreFilterstate, andonChangetriggers thehandleFilterChangefunction.<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 thebooksarray and renders each book as a list item. Thekeyattribute is set tobook._idto provide a unique identifier for each list item.
export default BookList;
Export Component
export default BookList: Exports theBookListcomponent as the default export of the module, making it available for import in other files.
Summary
- State Management: The component uses
useStateto manage thebooksandgenreFilterstate. - Data Fetching: The
fetchBooksfunction usesaxiosto fetch books from the backend, filtered by the selected genre. - Event Handling: The
handleFilterChangefunction updates thegenreFilterstate 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, anderrorstate variables as empty strings. ThesetTitle,setGenre, andsetErrorfunctions 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/booksendpoint with the book’stitleandgenre.- Response Handling:
- On success: Clears the input fields by setting
titleandgenreto empty strings, resetserrorto an empty string, and callsonBookAddedwith the new book data. - On failure: Sets the
errorstate 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 anonSubmithandler that triggers thehandleSubmitfunction.
- 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. Thevalueattribute is bound to thetitlestate, andonChangeupdates 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. Thevalueattribute is bound to thegenrestate, andonChangeupdates 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 theBookFormcomponent as the default export of the module, making it available for import in other files.
Summary
- State Management: The component uses
useStateto manage thetitle,genre, anderrorstate. - Form Handling: The
handleSubmitfunction handles form submission, sending a POST request to the backend to add a new book. - Event Handling: The input fields and select dropdown use
onChangehandlers to update the state. - Conditional Rendering: The error message is conditionally rendered based on the
errorstate. - 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 thecomponentsdirectory.BookForm: The component that provides a form for adding new books, imported from thecomponentsdirectory../App.css: The CSS file that contains styling for theAppcomponent.
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 thebooksstate variable as an empty array. ThesetBooksfunction 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
booksstate by appending the new book to the existing array of books. TheprevBooksargument represents the current state of thebooksarray, 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 nameAppfor styling.<h1>MERN Stack Filtering Application</h1>: A header for the application.
- Components:
<BookForm onBookAdded={handleBookAdded} />: Renders theBookFormcomponent and passes thehandleBookAddedfunction as a prop namedonBookAdded. This allows theBookFormto notify theAppcomponent when a new book is added.<BookList books={books} />: Renders theBookListcomponent and passes thebooksstate as a prop namedbooks. This allows theBookListto display the current list of books.
export default App;
Export component
export default App: Exports theAppcomponent as the default export of the module, making it available for import in other files.
Summary
- State Management: The
Appcomponent usesuseStateto manage thebooksstate, which holds the list of books. - Event Handling: The
handleBookAddedfunction updates thebooksstate when a new book is added. - Component Composition: The
Appcomponent renders theBookFormandBookListcomponents, passing necessary props to each. - Styling: The component uses a CSS class
Appfor 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.