Approach
- We will build a reusable student form with Formik and React-Bootstrap. This form has all the necessary fields to enter student details. We have also made client-side form validation with Yup. In the future, we will use this component for creating and update a student. Go to src/Components/StudentForm.js.
- We will create a component to add a new student. We have already created a StudentForm component to enter student details. Now, it’s time to use this component. Go to src/Components/create-student.component.js.
- We will create a component to update details. We have reusable StudentForm component, let’s use it again. We will fetch student details to reinitialise form. Go to src/Components/edit-student.component.js.
- We will build a component to display the student details in a table. We will fetch student’s data and iterate over it to create table row for every student. Go to src/Components/student-list.component.js.
- We will return table row which is responsible to display student data. Go to src/Components/StudentTableRow.js.
- Finally, include the menu to make routing in our MERN Stack CRUD app. Go to src/App.js and write the following code.
Javascript
//App.js // Import React import React from "react" ; // Import Bootstrap import { Nav, Navbar, Container, Row, Col } from "react-bootstrap" ; import "bootstrap/dist/css/bootstrap.css" ; // Import Custom CSS import "./App.css" ; // Import from react-router-dom import { BrowserRouter as Router, Switch, Route, Link } from "react-router-dom" ; // Import other React Component import CreateStudent from "./Components/create-student.component" ; import EditStudent from "./Components/edit-student.component" ; import StudentList from "./Components/student-list.component" ; // App Component const App = () => { return ( <Router> <div className= "App" > <header className= "App-header" > <Navbar bg= "dark" variant= "dark" > <Container> <Navbar.Brand> <Link to={ "/create-student" } className= "nav-link" > React MERN Stack App </Link> </Navbar.Brand> <Nav className= "justify-content-end" > <Nav> <Link to={ "/create-student" } className= "nav-link" > Create Student </Link> </Nav> <Nav> <Link to={ "/student-list" } className= "nav-link" > Student List </Link> </Nav> </Nav> </Container> </Navbar> </header> <Container> <Row> <Col md={12}> <div className= "wrapper" > <Switch> <Route exact path= "/" component={CreateStudent} /> <Route path= "/create-student" component={CreateStudent} /> <Route path= "/edit-student/:id" component={EditStudent} /> <Route path= "/student-list" component={StudentList} /> </Switch> </div> </Col> </Row> </Container> </div> </Router> ); }; export default App; |
Javascript
//src / Components / StudentForm.js import React from "react" ; import * as Yup from "yup" ; import { Formik, Form, Field, ErrorMessage } from "formik" ; import { FormGroup, FormControl, Button } from "react-bootstrap" ; const StudentForm = (props) => { const validationSchema = Yup.object().shape({ name: Yup.string().required( "Required" ), email: Yup.string() .email( `You have enter an invalid email address` ) .required( "Required" ), rollno: Yup.number() .positive( "Invalid roll number" ) .integer( "Invalid roll number" ) .required( "Required" ), }); console.log(props); return ( <div className= "form-wrapper" > <Formik {...props} validationSchema={validationSchema}> <Form> <FormGroup> <Field name= "name" type= "text" className= "form-control" /> <ErrorMessage name= "name" className= "d-block invalid-feedback" component= "span" /> </FormGroup> <FormGroup> <Field name= "email" type= "text" className= "form-control" /> <ErrorMessage name= "email" className= "d-block invalid-feedback" component= "span" /> </FormGroup> <FormGroup> <Field name= "rollno" type= "number" className= "form-control" /> <ErrorMessage name= "rollno" className= "d-block invalid-feedback" component= "span" /> </FormGroup> <Button variant= "danger" size= "lg" block= "block" type= "submit" > {props.children} </Button> </Form> </Formik> </div> ); }; export default StudentForm; |
Javascript
//src/Components/create-student.component.js // CreateStudent Component for add new student // Import Modules import React, { useState, useEffect } from "react" ; import axios from 'axios' ; import StudentForm from "./StudentForm" ; // CreateStudent Component const CreateStudent = () => { const [formValues, setFormValues] = useState( { name: '' , email: '' , rollno: '' }) // onSubmit handler const onSubmit = studentObject => { axios.post( 'http://localhost:4000/students/create-student' , studentObject) .then(res => { if (res.status === 200) alert( 'Student successfully created' ) else Promise.reject() }) . catch (err => alert( 'Something went wrong' )) } // Return student form return ( <StudentForm initialValues={formValues} onSubmit={onSubmit} enableReinitialize> Create Student </StudentForm> ) } // Export CreateStudent Component export default CreateStudent |
Javascript
//src/Components/edit-student.component.js // EditStudent Component for update student data // Import Modules import React, { useState, useEffect } from "react" ; import axios from "axios" ; import StudentForm from "./StudentForm" ; // EditStudent Component const EditStudent = (props) => { const [formValues, setFormValues] = useState( { name: "" , email: "" , rollno: "" , } ); //onSubmit handler const onSubmit = (studentObject) => { axios .put( "http://localhost:4000/students/update-student/" + props.match.params.id, studentObject ) .then((res) => { if (res.status === 200) { alert( "Student successfully updated" ); props.history.push( "/student-list" ); } else Promise.reject(); }) . catch ( (err) => alert( "Something went wrong" ) ); }; // Load data from server and reinitialize student form useEffect(() => { axios .get( "http://localhost:4000/students/update-student/" + props.match.params.id ) .then((res) => { const { name, email, rollno } = res.data; setFormValues( { name, email, rollno }); }) . catch ( (err) => console.log(err) ); }, []); // Return student form return ( <StudentForm initialValues={formValues} onSubmit={onSubmit} enableReinitialize> Update Student </StudentForm> ); }; // Export EditStudent Component export default EditStudent; |
Javascript
//src/Components/student-list.component.js import React, { useState, useEffect } from "react" ; import axios from "axios" ; import { Table } from "react-bootstrap" ; import StudentTableRow from "./StudentTableRow" ; const StudentList = () => { const [students, setStudents] = useState([]); useEffect(() => { axios .get( "http://localhost:4000/students/" ) .then(({ data }) => { setStudents(data); }) . catch ((error) => { console.log(error); }); }, []); const DataTable = () => { return students.map((res, i) => { return <StudentTableRow obj={res} key={i} />; }); }; return ( <div className= "table-wrapper" > <Table striped bordered hover> <thead> <tr> <th>Name</th> <th>Email</th> <th>Roll No</th> <th>Action</th> </tr> </thead> <tbody>{DataTable()}</tbody> </Table> </div> ); }; export default StudentList; |
Javascript
//src/Components/StudentTableRow.js import React from "react" ; import { Button } from "react-bootstrap" ; import { Link } from "react-router-dom" ; import axios from "axios" ; const StudentTableRow = (props) => { const { _id, name, email, rollno } = props.obj; const deleteStudent = () => { axios . delete ( "http://localhost:4000/students/delete-student/" + _id) .then((res) => { if (res.status === 200) { alert( "Student successfully deleted" ); window.location.reload(); } else Promise.reject(); }) . catch ( (err) => alert( "Something went wrong" )); }; return ( <tr> <td>{name}</td> <td>{email}</td> <td>{rollno}</td> <td> <Link className= "edit-link" to={ "/edit-student/" + _id}> Edit </Link> <Button onClick={deleteStudent} size= "sm" variant= "danger" > Delete </Button> </td> </tr> ); }; export default StudentTableRow; |
CSS
.wrapper { padding-top : 30px ; } body h 3 { margin-bottom : 25px ; } .navbar-brand a { color : #ffffff ; } .form-wrapper, .table-wrapper { max-width : 500px ; margin : 0 auto ; } .table-wrapper { max-width : 700px ; } .edit-link { padding : 7px 10px ; font-size : 0.875 rem; line-height : normal ; border-radius: 0.2 rem; color : #fff ; background-color : #28a745 ; border-color : #28a745 ; margin-right : 10px ; position : relative ; top : 1px ; } .edit-link:hover { text-decoration : none ; color : #ffffff ; } /* Chrome, Safari, Edge, Opera */ input::-webkit-outer-spin-button, input::-webkit-inner-spin-button { -webkit-appearance: none ; margin : 0 ; } /* Firefox */ input[type=number] { -moz-appearance: textfield; } |
Now, we have successfully created the frontend for our mern-stack-app. Let’s build the backend part. Before, jumping to next section take a look how the frontend part working without backend.
Step to Run the application: Open the terminal and type the following command.
npm start
Output:
How to build a basic CRUD app with Node and React ?
In this article, we will create a basic Student app from scratch using the MERN stack which will implement all the CRUD(Create, Read, Update and Delete) Operations.
Preview of final output: Let us have a look at how the final application will look like