En este artículo, crearemos una aplicación básica para estudiantes desde cero.
Funcionalidad de la aplicación:
- Crear un nuevo estudiante
- Actualizar un estudiante existente
- Mostrar lista de estudiantes
- Eliminar un estudiante
API REST en este proyecto:
API REST |
URL |
OBTENER | http://localhost:4000/estudiantes |
OBTENER | /estudiantes/actualizar-estudiante/id |
CORREO | /estudiantes/crear-estudiante |
PONER | /estudiantes/actualizar-estudiante/id |
ELIMINAR | /estudiantes/eliminar-estudiante/id |
En primer lugar, trabajaremos en la parte frontal de nuestra aplicación utilizando React.js.
Crear aplicación React e instalar módulos
Paso 1: Empecemos a construir la parte Front-end con React. Para crear una nueva aplicación React, ingrese el siguiente código en la terminal y presione enter.
npx create-react-app mern-stack-crud
Paso 2: Vaya a la carpeta del proyecto React.
cd mern-stack-crud
Paso 3: para ejecutar la aplicación React, ejecute el siguiente comando:
npm start
Este comando abre la aplicación React en el navegador en la siguiente URL: http://localhost:3000/
Paso 4: Para construir la aplicación React, necesitamos instalar algunos módulos externos.
MNP |
Detalle |
Reaccionar-Bootstrap | React-Bootstrap ha evolucionado y crecido junto con React, lo que lo convierte en una excelente opción para su interfaz de usuario. |
Reaccionar-Router-Dom | React Router DOM le permite implementar enrutamiento en una aplicación React. |
Axios | Es un cliente HTTP base de promesa y se usa para requests de red. |
Formik | Una gran biblioteca para construir formularios en React. |
Sí | Sí, es un generador de esquemas de JavaScript para la validación de formularios. |
Para instalar, ejecute el siguiente código en la terminal.
npm i react-bootstrap@next bootstrap@5.1.0 react-router-dom axios formik sí
Paso 5: Creación de componentes simples de React: en este paso, crearemos algunos componentes de React para administrar los datos de los estudiantes.
Diríjase a la carpeta src , cree una carpeta y asígnele el nombre Componentes y dentro de ese directorio cree los siguientes componentes.
- StudentForm.js – Formulario de estudiante reutilizable
- create-student.component.js – Responsable de crear un nuevo estudiante
- edit-student.component.js – Responsable de actualizar los datos de los estudiantes
- student-list.component.js – Responsable de mostrar todos los estudiantes
- StudentTableRow.js : responsable de mostrar un solo estudiante
Estructura del proyecto: se verá así
Paso 6: Crear formulario de estudiante: en este paso, crearemos un formulario de estudiante reutilizable con Formik y React-Bootstrap. Este formulario tiene todos los campos necesarios para ingresar los detalles del estudiante. También hemos realizado la validación de formularios del lado del cliente con Yup. En el futuro, utilizaremos este componente para crear y actualizar un alumno. Vaya a src/Components/StudentForm.js y escriba el siguiente código.
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;
Paso 7: Crear un nuevo estudiante: En este paso, crearemos un componente para agregar un nuevo estudiante. Ya hemos creado un componente StudentForm para ingresar los detalles del estudiante. Ahora, es el momento de utilizar este componente. Vaya a src/Components/create-student.component.js y escriba el siguiente código.
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
Paso 8: Actualizar los detalles del estudiante: En esta sección, crearemos un componente para actualizar los detalles. Tenemos un componente StudentForm reutilizable , usémoslo de nuevo. Buscaremos los detalles del estudiante para reiniciar el formulario. Vaya a src/Components/edit-student.component.js y escriba el siguiente código.
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;
Paso 9: Mostrar la lista de estudiantes: En este paso, crearemos un componente para mostrar los detalles de los estudiantes en una tabla. Obtendremos los datos de los estudiantes y los repetiremos para crear una fila de tabla para cada estudiante. Vaya a src/Components/student-list.component.js y escriba el siguiente código.
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;
Paso 10: Mostrar un solo estudiante: En este paso, devolveremos la fila de la tabla que es responsable de mostrar los datos de los estudiantes. Vaya a src/Components/StudentTableRow.js y escriba el siguiente código.
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;
Paso 11: Edite App.js: Finalmente, incluya el menú para hacer enrutamiento en nuestra aplicación MERN Stack CRUD. Vaya a src/App.js y escriba el siguiente código.
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;
Paso 12: Agregar estilo: vaya a src/App.css y escriba el siguiente código.
App.css
.wrapper { padding-top: 30px; } body h3 { 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.875rem; line-height: normal; border-radius: 0.2rem; 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; }
Ahora, hemos creado con éxito la interfaz para nuestra mern-stack-app . Vamos a construir la parte de backend. Antes, saltando a la siguiente sección, observe cómo funciona la parte frontal sin backend.
Paso para ejecutar la aplicación: Abra la terminal y escriba el siguiente comando.
npm start
Producción:
Ahora trabajaremos en la parte de backend de nuestra aplicación. Crearemos una carpeta dentro de nuestro mern-stack-crud para administrar los servicios del servidor, como la base de datos, los modelos, el esquema, las rutas y las API; nombre esta carpeta backend .
Paso 1: Ejecute el comando para crear una carpeta de back -end para el servidor y acceda a ella.
mkdir backend && cd backend
Paso 2: Crear package.json: a continuación, debemos crear un archivo package.json separado para administrar el servidor de nuestra aplicación mern-stack-crud .
npm init -y
Vaya al archivo backend/package.json que tendrá el siguiente aspecto. Reemplace la propiedad de prueba como:
"test": "echo \"Error: no test specified\" && exit 1""start": "nodemon server.js"
Paso 3: Instalar dependencias de Nodes: instale las siguientes dependencias de Nodes.
MNP |
Detalle |
Expresar | Marco Node.js que ayuda a crear potentes API REST. |
analizador de cuerpo | Extrae la parte del cuerpo completo de un flujo de solicitud y lo expone en req.body. |
corazones | Es un paquete de Node.js que ayuda a habilitar el encabezado CORS Access-Control-Allow-Origin. |
mangosta | Es una base de datos NoSQL para crear una aplicación web robusta. |
Para instalar las dependencias anteriores, ejecute el siguiente código en la terminal.
npm install express body-parser cors mongoose
Puede instalar nodemon como dependencia de desarrollo para automatizar el proceso de reinicio del servidor.
npm i -D nodemon
Estructura del proyecto de back-end
Paso 4: Configuración de la base de datos MongoDB: en este paso, configuraremos una base de datos MongoDB para nuestra aplicación. Antes de comenzar, asegúrese de tener instalada la última versión de MongoDB en su sistema. Cree una carpeta dentro de la carpeta backend y asígnele el nombre base de datos . Cree un archivo con el nombre de db.js dentro de la carpeta de la base de datos . Vaya a backend/database/db.js y escriba el siguiente código.
db.js
module.exports = { db: 'mongodb://localhost:27017/reactdb' };
Hemos declarado la base de datos MongoDB y la hemos llamado reactdb .
Paso 5: Defina el esquema Mongoose: ahora, cree el esquema MongoDB para interactuar con la base de datos MongoDB. Cree una carpeta llamada models dentro de la carpeta back -end para mantener los archivos relacionados con el esquema y cree un archivo Student.js dentro de ella para definir el esquema de MongoDB. Vaya a backend/models/Student.js y escriba el siguiente código.
Student.js
const mongoose = require('mongoose'); const Schema = mongoose.Schema; let studentSchema = new Schema({ name: { type: String }, email: { type: String }, rollno: { type: Number } }, { collection: 'students' }) module.exports = mongoose.model('Student', studentSchema)
Declaramos los campos de nombre, correo electrónico y rollno junto con sus respectivos tipos de datos en el esquema del estudiante.
Paso 6: Cree rutas usando ExpressJS: en este paso, configuramos algunas rutas (API REST) para CREAR, LEER, ACTUALIZAR y ELIMINAR usando Express y Node.js. Estas rutas nos ayudarán a administrar los datos en nuestra aplicación mern-stack-crud . Cree una carpeta y asígnele el nombre rutas dentro de la carpeta backend. Aquí guardaremos todos los archivos relacionados con las rutas. Además, cree un archivo y asígnele el nombre student.routes.js dentro de la carpeta de rutas , en este archivo definiremos nuestras rutas.
mkdir routes && cd routes && touch student.route.js
Luego, vaya al archivo backend/routes/student.route.js y escriba el siguiente código.
student.route.js
let mongoose = require("mongoose"), express = require("express"), router = express.Router(); // Student Model let studentSchema = require("../models/Student"); // CREATE Student router.post("/create-student", (req, res, next) => { studentSchema.create(req.body, (error, data) => { if (error) { return next(error); } else { console.log(data); res.json(data); } }); }); // READ Students router.get("/", (req, res) => { studentSchema.find((error, data) => { if (error) { return next(error); } else { res.json(data); } }); }); // UPDATE student router .route("/update-student/:id") // Get Single Student .get((req, res) => { studentSchema.findById( req.params.id, (error, data) => { if (error) { return next(error); } else { res.json(data); } }); }) // Update Student Data .put((req, res, next) => { studentSchema.findByIdAndUpdate( req.params.id, { $set: req.body, }, (error, data) => { if (error) { return next(error); console.log(error); } else { res.json(data); console.log("Student updated successfully !"); } } ); }); // Delete Student router.delete("/delete-student/:id", (req, res, next) => { studentSchema.findByIdAndRemove( req.params.id, (error, data) => { if (error) { return next(error); } else { res.status(200).json({ msg: data, }); } }); }); module.exports = router;
Paso 7: Configure server.js: casi hemos creado todo para nuestra aplicación mern-stack-crud . Ahora, cree el archivo server.js en la raíz de la carpeta backend . Vaya a backend/server.js y escriba el siguiente código.
server.js
let express = require('express'); let mongoose = require('mongoose'); let cors = require('cors'); let bodyParser = require('body-parser'); let dbConfig = require('./database/db'); // Express Route const studentRoute = require('../backend/routes/student.route') // Configure mongoDB Database mongoose.set('useNewUrlParser', true); mongoose.set('useFindAndModify', false); mongoose.set('useCreateIndex', true); mongoose.set('useUnifiedTopology', true); // Connecting MongoDB Database mongoose.Promise = global.Promise; mongoose.connect(dbConfig.db).then(() => { console.log('Database successfully connected!') }, error => { console.log('Could not connect to database : ' + error) } ) const app = express(); app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: true })); app.use(cors()); app.use('/students', studentRoute) // PORT const port = process.env.PORT || 4000; const server = app.listen(port, () => { console.log('Connected to port ' + port) }) // 404 Error app.use((req, res, next) => { res.status(404).send('Error 404!') }); app.use(function (err, req, res, next) { console.error(err.message); if (!err.statusCode) err.statusCode = 500; res.status(err.statusCode).send(err.message); });
Ahora, hemos creado con éxito el backend para nuestra mern-stack-app .
Nuestra estructura final de directorios del proyecto:
Ahora, inicie el servidor de base de datos MongoDB para ejecutar el servidor.
Paso para ejecutar la aplicación: abra una terminal y ejecute el siguiente comando para iniciar el servidor Nodemon permaneciendo en la carpeta backend .
npm start
Si todo funciona bien, verá el siguiente resultado en la pantalla del terminal.
resultado final: