Architectural Design Pattern‐2(MVT) - nighttourist/Batch-Management-System GitHub Wiki
Author-Md. Niaz Rahaman
MVT can be adapted in a React and Node.js context:
In a React and Node.js application, the Model typically represents the data and business logic.
- Node.js: The Model often resides on the server-side in Node.js. This might involve interacting with databases, managing application state, or handling business rules. You might use libraries or frameworks like Sequelize (for SQL databases) to define and manage models.
-
React: On the client-side, you can manage local state using tools like
useState
oruseReducer
hooks, or use state management libraries like Redux or Zustand. While this is not exactly the same as a traditional model, it serves a similar purpose by managing and processing data used by the components.
In the MVT context for React:
- React Components: These serve as the View. React components are responsible for rendering the UI and presenting data to the user. They handle user interactions and display information, reacting to changes in state or props.
-
React Hooks: Hooks like
useEffect
can manage side effects and interact with the data or Model. The View components might call functions from the Model or update the state based on the Model's responses.
In a React and Node.js setup:
- React JSX: JSX (JavaScript XML) serves as the Template. It allows you to write HTML structures within JavaScript code, enabling dynamic rendering of content based on the Model's data. JSX templates are used to build the UI components and display data in a structured manner.
- Server-Side Rendering (SSR): If you use Node.js for SSR with frameworks like Next.js, the server might render pages on the fly using templates before sending them to the client. This can involve embedding data from the server into HTML templates before delivery.
JSX (JavaScript XML) is a syntax extension for JavaScript that is commonly used with React to describe what the UI should look like. It allows you to write HTML-like code directly within JavaScript, making it easier to create and manage UI components. JSX combines the power of JavaScript with the simplicity of HTML.
- Declarative Syntax: JSX allows you to write components in a way that looks similar to HTML, making the structure of your UI more readable and declarative.
-
Embedding Expressions: You can embed JavaScript expressions within JSX using curly braces
{}
. This allows you to dynamically insert values and expressions into your markup. - Component Composition: JSX makes it straightforward to compose and nest components. This promotes reusable UI elements and modular design.
- JavaScript Integration: Because JSX is ultimately transpiled into JavaScript, you can use all JavaScript features within JSX, including variables, functions, and conditionals.
Sequelize is a popular Object-Relational Mapping (ORM) library for Node.js that provides a powerful and flexible way to interact with SQL databases. It allows you to work with relational databases using JavaScript objects and methods, abstracting away much of the complexity of SQL queries.
- Model Definition: Sequelize allows you to define models that represent tables in your database. Each model maps to a table, and each instance of a model maps to a row in that table.
- Associations: Sequelize supports associations (relationships) between models, such as one-to-one, one-to-many, and many-to-many relationships. This helps manage complex relationships between tables.
- Migration Support: Sequelize provides a migration system that allows you to version control your database schema. Migrations are used to apply changes to your database schema over time.
- Querying: Sequelize provides a rich set of methods for querying the database, including CRUD operations (Create, Read, Update, Delete) and complex queries with filtering, sorting, and pagination.
- Transactions: Sequelize supports transactions, which allow you to group multiple database operations into a single unit of work. This ensures that either all operations are completed successfully or none are, maintaining data integrity.
- Hooks: Sequelize has hooks (or lifecycle events) that let you run custom code before or after certain actions, such as saving or deleting records.
Here’s how you can apply the MVT architecture using SQL databases such as MySQL , along with an ORM like Sequelize.
The model represents the data layer, where you define the structure of your database tables and interact with the database using Sequelize.
Example with Sequelize:
-
Install Dependencies:
npm install sequelize sequelize-cli mysql2
-
Initialize Sequelize:
`npx sequelize-cli init`
This command creates a basic folder structure:
arduino
├── config
├── models
├── migrations
├── seeders
Define a Model: Create a model file in the models
folder.
javascript
// models/student.js
module.exports = (sequelize, DataTypes) => {
const Student = sequelize.define('Student', {
firstName: {
type: DataTypes.STRING,
allowNull: false,
},
lastName: {
type: DataTypes.STRING,
allowNull: false,
},
age: {
type: DataTypes.INTEGER,
allowNull: false,
},
});
return Student;
};
Create and Apply Migrations: Generate a migration file:
npx sequelize-cli migration:generate --name create-student
Edit the migration file in the migrations
folder:
javascript
// migrations/20210918123456-create-student.js
'use strict';
module.exports = {
up: async (queryInterface, Sequelize) => {
await queryInterface.createTable('Students', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER,
},
firstName: {
type: Sequelize.STRING,
allowNull: false,
},
lastName: {
type: Sequelize.STRING,
allowNull: false,
},
age: {
type: Sequelize.INTEGER,
allowNull: false,
},
createdAt: {
allowNull: false,
type: Sequelize.DATE,
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE,
},
});
},
down: async (queryInterface, Sequelize) => {
await queryInterface.dropTable('Students');
},
};
Apply the migration:
npx sequelize-cli db:migrate
In React, the view is represented by components that fetch data from the backend and display it in the UI. React components interact with the backend APIs and render the data.
Example React Component:
jsx
// src/components/StudentList.js
import React, { useEffect, useState } from 'react';
const StudentList = () => {
const [students, setStudents] = useState([]);
useEffect(() => {
fetch('/api/students')
.then(response => response.json())
.then(data => setStudents(data))
.catch(error => console.error('Error fetching data:', error));
}, []);
return (
<div>
<h1>Student List</h1>
<ul>
{students.map(student => (
<li key={student.id}>
{student.firstName} {student.lastName} - Age: {student.age}
</li>
))}
</ul>
</div>
);
};
export default StudentList;
The template in this case is the JSX structure in your React components, which defines how the data is displayed.
Example JSX Template:
jsx
// This is part of the StudentList component above
return (
<div>
<h1>Student List</h1>
<ul>
{students.map(student => (
<li key={student.id}>
{student.firstName} {student.lastName} - Age: {student.age}
</li>
))}
</ul>
</div>
);
Create an Express Server:
javascript
// server.js
const express = require('express');
const { Sequelize, DataTypes } = require('sequelize');
const Student = require('./models/student');
const app = express();
app.use(express.json());
// Connect to the SQL database
const sequelize = new Sequelize('database', 'username', 'password', {
host: 'localhost',
dialect: 'mysql', // or 'postgres'
});
// Initialize model
const StudentModel = Student(sequelize, DataTypes);
// API Endpoint to get students
app.get('/api/students', async (req, res) => {
try {
const students = await StudentModel.findAll();
res.json(students);
} catch (err) {
res.status(500).json({ message: err.message });
}
});
app.listen(5000, () => {
console.log('Server is running on port 5000');
});
React Component:
jsx
// src/components/StudentList.js
import React, { useEffect, useState } from 'react';
const StudentList = () => {
const [students, setStudents] = useState([]);
useEffect(() => {
fetch('/api/students')
.then(response => response.json())
.then(data => setStudents(data))
.catch(error => console.error('Error fetching data:', error));
}, []);
return (
<div>
<h1>Student List</h1>
<ul>
{students.map(student => (
<li key={student.id}>
{student.firstName} {student.lastName} - Age: {student.age}
</li>
))}
</ul>
</div>
);
};
export default StudentList;
In your React app, make sure you have the proxy set up in package.json
:
json
{
"proxy": "http://localhost:5000"
}
This setup uses a RESTful API with Node.js, Express, and Sequelize as the backend, and React for the frontend. The "Model" is represented by Sequelize models, the "View" by React components, and the "Template" by the JSX/HTML structure within those components.
- Model: Handled by Node.js on the server side, managing the todo data and providing endpoints for data retrieval and manipulation.
- View: Implemented by React components, rendering the user interface and managing interactions.
- Template: Defined using JSX within React components, structuring how data is presented in the UI.