In this lesson, we will build a simple React Student Management Dashboard. This mini project combines important React concepts learned throughout the tutorial, including components, props, state, events, forms, lists, conditional rendering, and reusable UI.
Our project will contain a simple student dashboard.
Student Management App
↓
┌──────┼────────┐
↓ ↓ ↓
Add Search Student List
Student Students
↓
Delete
Student
This project demonstrates how different React concepts work together.
src/
├── components/
│ ├── Header.jsx
│ ├── StudentForm.jsx
│ ├── StudentList.jsx
│ └── StudentCard.jsx
│
├── App.jsx
└── main.jsx
Separating the application into components makes the project easier to understand and maintain.
Each student can be represented by an object.
const student = {
id: 1,
name: "Amit",
email: "amit@example.com",
course: "React"
};
The application can store multiple student objects inside an array.
const initialStudents = [
{
id: 1,
name: "Amit",
email: "amit@example.com",
course: "React"
},
{
id: 2,
name: "Neha",
email: "neha@example.com",
course: "JavaScript"
},
{
id: 3,
name: "Rahul",
email: "rahul@example.com",
course: "Python"
}
];
The student list can be stored using useState.
const [students, setStudents] =
useState(initialStudents);
Calling setStudents() updates the student list and causes the
component to render again.
We can store the search text in another state variable.
const [search, setSearch] =
useState("");
The value changes when the user types into the search box.
The form can contain fields for student name, email, and course.
<form>
<input
type="text"
placeholder="Student Name"
/>
<input
type="email"
placeholder="Email"
/>
<input
type="text"
placeholder="Course"
/>
<button type="submit">
Add Student
</button>
</form>
The form fields can be controlled using a state object.
const [form, setForm] =
useState({
name: "",
email: "",
course: ""
});
A reusable change handler can update individual fields.
function handleChange(e) {
const {
name,
value
} = e.target;
setForm({
...form,
[name]: value
});
}
A controlled input gets its value from React state.
<input
name="name"
value={form.name}
onChange={handleChange}
placeholder="Student Name"
/>
React becomes the source of truth for the input value.
The form submission handler can prevent the browser's default page reload.
function handleSubmit(e) {
e.preventDefault();
// Add student here
}
Before adding a student, required fields should be checked.
if (
!form.name ||
!form.email ||
!form.course
) {
setError(
"All fields are required"
);
return;
}
The application can display validation errors using another state variable.
const [error, setError] =
useState("");
When the form is valid, the error can be cleared.
setError("");
After validation, a new student object can be added to the array.
const newStudent = {
id: Date.now(),
name: form.name,
email: form.email,
course: form.course
};
setStudents([
...students,
newStudent
]);
After successfully adding a student, reset the form fields.
setForm({
name: "",
email: "",
course: ""
});
This prepares the form for the next student.
<input
type="text"
value={search}
onChange={e =>
setSearch(
e.target.value
)
}
placeholder="Search students"
/>
The search state changes as the user types.
The student array can be filtered using the search text.
const filteredStudents =
students.filter(student =>
student.name
.toLowerCase()
.includes(
search.toLowerCase()
)
);
The filtered student array can be displayed using map().
{filteredStudents.map(
student => (
<div key={student.id}>
<h3>
{student.name}
</h3>
<p>
{student.email}
</p>
<p>
{student.course}
</p>
</div>
))}
A separate component can display one student.
function StudentCard({
student,
onDelete
}) {
return (
<div className="card mb-3">
<div className="card-body">
<h5>
{student.name}
</h5>
<p>
{student.email}
</p>
<p>
{student.course}
</p>
<button
className="btn btn-danger"
onClick={() =>
onDelete(
student.id
)
}
>
Delete
</button>
</div>
</div>
);
}
The filter() method can create a new array without the selected
student.
function handleDelete(id) {
setStudents(
students.filter(
student =>
student.id !== id
)
);
}
The parent can pass the delete function to the student component.
<StudentCard
key={student.id}
student={student}
onDelete={handleDelete}
/>
This demonstrates communication from a child component back to the parent through a callback prop.
The number of students can be displayed using the array's
length property.
<h3>
Total Students:
{students.length}
</h3>
If there are no matching students, display a message.
{filteredStudents.length === 0 ? (
<p>
No students found.
</p>
) : (
filteredStudents.map(
student => (
<StudentCard
key={student.id}
student={student}
onDelete={handleDelete}
/>
)
)
)}
function StudentCard({
student,
onDelete
}) {
return (
<div className="card mb-3 shadow-sm">
<div className="card-body">
<h5 className="card-title">
{student.name}
</h5>
<p className="card-text">
Email:
{student.email}
</p>
<p className="card-text">
Course:
{student.course}
</p>
<button
className="btn btn-danger"
onClick={() =>
onDelete(
student.id
)
}
>
Delete
</button>
</div>
</div>
);
}
export default StudentCard;
import {
useState
} from "react";
function StudentForm({
onAdd
}) {
const [form, setForm] =
useState({
name: "",
email: "",
course: ""
});
const [error, setError] =
useState("");
function handleChange(e) {
const {
name,
value
} = e.target;
setForm({
...form,
[name]: value
});
}
function handleSubmit(e) {
e.preventDefault();
if (
!form.name ||
!form.email ||
!form.course
) {
setError(
"All fields are required"
);
return;
}
setError("");
onAdd(form);
setForm({
name: "",
email: "",
course: ""
});
}
return (
<form
onSubmit={handleSubmit}
className="mb-4"
>
{error && (
<div className="alert alert-danger">
{error}
</div>
)}
<input
name="name"
value={form.name}
onChange={handleChange}
placeholder="Student Name"
className="form-control mb-2"
/>
<input
name="email"
type="email"
value={form.email}
onChange={handleChange}
placeholder="Email"
className="form-control mb-2"
/>
<input
name="course"
value={form.course}
onChange={handleChange}
placeholder="Course"
className="form-control mb-2"
/>
<button
className="btn btn-primary"
type="submit"
>
Add Student
</button>
</form>
);
}
export default StudentForm;
import StudentCard
from "./StudentCard";
function StudentList({
students,
onDelete
}) {
if (students.length === 0) {
return (
<p>
No students found.
</p>
);
}
return (
<div>
{students.map(
student => (
<StudentCard
key={student.id}
student={student}
onDelete={onDelete}
/>
))}
</div>
);
}
export default StudentList;
The import should normally be written on one line:
import StudentCard from "./StudentCard";
import {
useState
} from "react";
import StudentForm
from "./components/StudentForm";
import StudentList
from "./components/StudentList";
function App() {
const [students, setStudents] =
useState([
{
id: 1,
name: "Amit",
email: "amit@example.com",
course: "React"
},
{
id: 2,
name: "Neha",
email: "neha@example.com",
course: "JavaScript"
}
]);
const [search, setSearch] =
useState("");
function addStudent(student) {
const newStudent = {
...student,
id: Date.now()
};
setStudents([
...students,
newStudent
]);
}
function deleteStudent(id) {
setStudents(
students.filter(
student =>
student.id !== id
)
);
}
const filteredStudents =
students.filter(student =>
student.name
.toLowerCase()
.includes(
search.toLowerCase()
)
);
return (
<div className="container mt-4">
<h1 className="mb-4">
Student Management
</h1>
<StudentForm
onAdd={addStudent}
/>
<input
className="form-control mb-3"
placeholder="Search students"
value={search}
onChange={e =>
setSearch(
e.target.value
)
}
/>
<h3>
Total Students:
{students.length}
</h3>
<StudentList
students={
filteredStudents
}
onDelete={
deleteStudent
}
/>
</div>
);
}
export default App;
App
↓
StudentForm
↓
Add Student
↓
students State
↓
Filter by Search
↓
StudentList
↓
StudentCard
↓
Delete Student
↓
Update students State
This project combines several React concepts:
useStatemap()filter()React Components
↓
State
↓
Events
↓
Props
↓
UI Updates
useState can manage student records and form data.map() can render a list of students.filter() can implement searching and deleting.Question: Which React feature is commonly used to store and update the list of students in this mini project?