使用强大的堆栈Mern构建Web应用程序
#react #node #express #mongodb

堆栈逐步逐步逐步:从Innio到实际项目中使用

堆栈Mern是一组广泛用于开发现代有效的Web应用程序的技术。只不过是这4种技术:MongoDBExpress.jsReactNode.js,此堆栈为创作提供了完整的全堆栈方法。在本文中,我们将探索Stack Mern的每个组成部分,其独特的特征以及在我的感知之后研究它的prons和缺点,我在使用它时所拥有的,从逻辑上讲,我总是说,每个人都可以拥有自己的实践。优势。或缺点,除了使用此堆栈留下Web应用程序真实用例的示例。

此堆栈被分配如下,React在客户端的一侧,应用程序的前端到处都是责任被用作应用程序数据库。

还有另一个与此堆栈非常相似的堆栈,这是指基本同样的事情,代替React付款,使用Angular来管理应用程序的前端部分。

我将以简短的方式在这里谈论每个技术在这里不要伸展很多。

1. MongoDB

mongoDB是一个面向文档的NOQL数据库,可为应用程序提供灵活性和可扩展性。

优点:

  • 方案的灵活性:文档以JSON样(BSON)格式存储,允许这些方案通过开发调整更改。
  • 水平可伸缩性:MongoDB支持集群中的数据分布,随着颤抖的增加而促进能力的增加。
  • 快速发展:缺乏粗鲁的计划加速了发展过程,允许更多的社会迭代。

缺点:

  • 建模复杂性:定义方案的戒指可能会导致误解模型,需要仔细的建模方法。
  • 不适合关系数据:在使用数据库NOSQL时,强烈依赖于数据之间的复杂关系的应用程序就像MongoDB一样。

2. Express.js

express.js是node.js中Web应用程序创建的框架。它简化了API的创建和路线和请求的处理。

优点:

  • 简单性:Express提供了一种极简主义的方法,使开发人员可以快速创建端点并设置中间件。
  • 大型社区和文档:作为Node.js最受欢迎的框架之一,Express具有活跃而庞大的文档社区。

缺点:

  • 灵活的结构:缺乏坚固的结构会导致守则组织的不一致,尤其是在较大的项目中。

3. React

React是由Facebook开发的JavaScript库,旨在在客户端构建交互式和反应性用户界面。

优点:

  • 组件:React促进了可重复使用的组件的创建,简化了开发和维护。
  • 渲染效率:使用虚拟礼物的概念,React仅更新界面的必要部分,改善了性能。

缺点:

  • 初始学习曲线:对于组件和JSX概念中的新开发人员,可能有初始学习曲线。

4. Node.js

node.js是服务器端的JavaScript执行的环境。它允许开发人员构建Scald和实时Web应用程序。

优点:

  • JavaScript统一:在整个堆栈中使用相同的语言(JavaScript)简化了开发人员之间的通信和协作。
  • 阻塞:node.js的I/S非块的模型允许在依赖于I/O。
  • 的许多操作的应用中进行高性能和可伸缩性。

缺点:

  • 事件管理:基于事件的模型可以在复杂控制流的情况下制成复杂的代码。

这些是我多年来使用此堆栈发现的一些优势和缺点,它将有许多其他堆栈,但这是附近文章的主题。随意同意或不同意我在这里提到的观点。

研究堆栈Mern的优势

  1. 现代技术:堆栈Mern由更新的技术组成,并在流中广泛采用。
  2. 灵活性:技术的灵活性使我们能够适应不同类型的项目和要求。
  3. 活跃的社区:每个堆栈组成部分都有一个活跃的社区,促进获得支持并包含学习和学习。
  4. 统一的语言:您可以用JavaScript编写所有内容,而无需学习曲线以在跨越的某些技术中使用另一种语言。

研究堆栈Mern的缺点

  1. 学习曲线:每种技术都有自己的学习曲线,这对新手开发人员可能具有挑战性。
  2. 复杂性:四种不同技术的集成可以增加发展的复杂性和Depuel。
  3. 进化技术:技术可以迅速发展,要求开发人员不断更新。

在这里指出我发现的堆栈的实践和缺点,我将举一个用例,说明如何在真实项目上使用它。

在一个真实的项目中使用堆栈Mern

在本文中,我将举一个真实应用程序的简单示例,这将是列表,用户可以在其中添加其任务(to),并在需要时进行更新,然后将其删除,这些都将其发送到我们的API,您将在我们的数据库中坚持下去。

前端daaplica㧣o

让我们从使用React在客户方面的前端创建我们的应用程序,以执行以下命令:

npx create-react-app todo_list — template typescript

apits这将使用一些libs,可以使像Axios这样的项目的创建变得更加容易,而在我们对API进行呼吁时,我不会对此进行很多专注,我选择了使用MaterialUI的组件。

npm install @mui/material axios @mui/icons-material — save

我选择使用与CRA相关的CRA,我看到了准备启动应用程序的资源,我们会进行改进,有很多我们不会使用它,并且只留下它的重要性,毕竟它是您的结构项目将是这样的。

Arquitetura React front-end

当我在项目中使用TypeScript时,我必须创建一个名为type的文件夹,以便我可以手动指示本文本文未本地键入本文时的材料图标库,因此它是名称的文件夹类型 src 内部,并在其中创建一个称为 youm> model.d.t.ts 的文件,并添加以下段落。

declare module '@mui/icons-material/Delete' {
    import { SvgIconProps } from '@mui/material/SvgIcon';

    const DeleteIcon: (props: SvgIconProps) => JSX.Element;
    export default DeleteIcon;
  }

完成此操作后,打字稿将在将来在代码中调用此lib时停止给出倾斜错误。

甚至在使用堆栈Mern的其他技术创建我们的后端之前,让我们已经准备好前端,因此创建一个名为 server no no src 的文件夹,并在其中创建一个称为 api.t.t. 的文件,在此文件中,您可以通过Axios进行以下调用。

import axios, { AxiosResponse } from "axios";

const baseUrl = "http://localhost:3001/toDos";

const api = axios.create({ baseURL: baseUrl });

export interface ToDo {
  _id: string;
  text: string;
  completed: boolean;
}

export const fetchToDos = async (): Promise<ToDo[]> => {
  try {
    const response: AxiosResponse<ToDo[]> = await api.get(baseUrl);
    return response.data;
  } catch (error) {
    console.error("Error fetching toDos:", error);
    throw error;
  }
};

export const addToDo = async (task: {
  text: string;
  completed: boolean;
}): Promise<void> => {
  try {
    await api.post(baseUrl, task);
  } catch (error) {
    console.error("Error adding toDo:", error);
    throw error;
  }
};

export const toggleToDo = async (
  toDoId: string,
  completed: boolean
): Promise<void> => {
  try {
    await api.put(`${baseUrl}/${toDoId}`, { completed: !completed });
  } catch (error) {
    console.error("Error toggling toDo:", error);
    throw error;
  }
};

export const deleteToDo = async (toDoId: string): Promise<void> => {
  try {
    await api.delete(`${baseUrl}/${toDoId}`);
  } catch (error) {
    console.error("Error deleting toDo:", error);
    throw error;
  }
};

完成此操作后,我们的未来路线将被配置为我们的应用程序中的Axios并导出了我们的所有母亲的所有母亲,我们现在将将其导入我们的主文件 app <>。

import React, { useState, useEffect } from "react";
import {
  Container,
  TextField,
  Button,
  List,
  ListItem,
  ListItemText,
  Checkbox,
  IconButton,
} from "@mui/material";
import DeleteIcon from "@mui/icons-material/Delete";
import {
  ToDo,
  fetchToDos,
  addToDo,
  toggleToDo,
  deleteToDo,
} from "./server/api";

function App() {
  const [toDos, setToDos] = useState<ToDo[]>([]);
  const [toDoText, setToDoText] = useState<string>("");

  useEffect(() => {
    loadToDos();
  }, []);

  const loadToDos = async () => {
    const fetchedToDos = await fetchToDos();
    setToDos(fetchedToDos);
  };

  const handleAddToDo = async () => {
    if (toDoText.trim() === "") return;

    await addToDo({ text: toDoText, completed: false });
    setToDoText("");
    loadToDos();
  };

  const handleToggleToDo = async (toDoId: string, completed: boolean) => {
    await toggleToDo(toDoId, completed);
    loadToDos();
  };

  const handleDeleteToDo = async (toDoId: string) => {
    await deleteToDo(toDoId);
    loadToDos();
  };

  return (
    <Container>
      <h1>To Do List</h1>
      <TextField
        label="Adicionar To Do"
        variant="outlined"
        fullWidth
        value={toDoText}
        onChange={(e) => setToDoText(e.target.value)}
      />
      <Button variant="contained" onClick={handleAddToDo}>
        Adicionar
      </Button>
      <List>
        {toDos.map((toDo) => (
          <ListItem key={toDo._id}>
            <Checkbox
              checked={toDo.completed}
              onChange={() => handleToggleToDo(toDo._id, toDo.completed)}
            />
            <ListItemText primary={toDo.text} />
            <IconButton onClick={() => handleDeleteToDo(toDo._id)}>
              <DeleteIcon />
            </IconButton>
          </ListItem>
        ))}
      </List>
    </Container>
  );
}

export default App;

准备好我们的前端是按时间完成的,因此您可以看到下面的示例,仍然没有办法添加,因为路线仍然是在我们的背部创建的 - 现在,让我们立即创建它们。

Aplicação TO DO front-end

后端daaplica㧣o

要在nodejs和express.js中创建我们的后端。我们将执行以下操作。首先创建一个称为 all_list_api 的文件夹,然后在此文件夹中运行以下命令:

npm init -y

这将创建我们对package.json的配置,这是围绕以下命令来安装express.js和mongoose,这是一个用于node.js的对象建模库,旨在与mongodb一起使用,这将使组装变得更加容易。我们的模式。

npm install express mongoose

apits这也将安装和配置打字稿以与之使用。

npm install typescript@latest — save-dev

此命令将在当时安装最新版本的打字稿,这对于传递打字稿编译器的配置是必要的,因此,请在项目的根部创建一个名为 tsconfig.json的项目的文件。 ,内部粘贴了以下摘录,从có³doda中,这基本上是在我们的项目中使用Typescript的一些基本配置,除此之外,还有很多其他配置,只是它们。

{
    "compilerOptions": {
      "target": "ES2018",
      "module": "commonjs",
      "outDir": "./dist",
      "rootDir": "./src",
      "strict": true,
      "esModuleInterop": true
    }
  }

我们还需要在我们的代码中安装此lib。

npm install — save-dev ts-node

ts-node是一种工具,允许您直接在node.js中执行打字稿文件,而无需编译到。

可能是您要安装的某些lib您需要您的 @Types ,因此他们正在寻找网络或文档文档中的文档。£o,您认为要安装,如果您需要依靠使用的版本。

让我们推进并安装另一个库,以从环境中拯救我们的差异,在拨打MongoDB地图集时,不要以我们的登录和密码的方式暴露,这已经是一个crontic安全失败,为此,我们将使用称为dotenv的lib。

npm install dotenv

完成此操作,我们将在我们的项目的根部创建一个文件,称为 .env ,开始可以使其变得空,这将是我们的环境变量存储库,请记住创建一个称为 .gitignore 的文件,然后忽略它。

apons这是完成的,让我们创建我们的文件夹结构,以便在API中更有条理,就我而言,我正在使用分层的体系结构模式。在此标准中,该过程以不同的层进行组织,每个层都有特定的责任。我们将在此示例中使用的最常见层是模型,控制器,存储库和服务,我很快将创建一篇文章,解释该模式的原因是每种模式的良好实践,但对于不£o缝制很多只需每小时遵循此结构,继续该项目即可。

Arquitetura Nodejs back-end

我在上面的示例中创建了我们将需要的所有结构,并将它们各自的空文件到当下,并且我们将开始编纂,就像可以看出,大多数文件夹都有 index file ,这通常是一个很好的实用性,因为当我导入时,因为编译器默认情况下始终在索引值中寻找索引值,如果它必须在“导入”时指定文件名中的文件名。

让我们从应用程序开始对数据进行建模,所以让我们创建模型,我们已经通过Mongoose准备了我们的模式,以说明MongoDB的认股权证。

import { Document, Schema, model } from "mongoose";

export interface toDo extends Document {
  text: string;
  completed: boolean;
}

const toDoSchema: Schema = new Schema({
  text: { type: String, required: true },
  completed: { type: Boolean, required: false },
});

export default model<toDo>("toDo", toDoSchema);

完成此操作,已经创建了模型,我们现在将与数据库建立我们的连接,在我们的情况下,我将使用Mongo Atlas,它是托管和操作云中的MongoDB数据库的预测解决方案。

为此,您必须在MongoDB网站上拥有一个帐户,才能在Mongo Atlas创建一个集群。

novo projeto mongo atlas

您必须创建一个与之合作的项目,您只需单击 您在项目中还有更多,在我们的情况下,您是在您的帐户中注册的电子邮件,默认情况下将是项目所有者。

novo database

这是至关重要的部分,如果您查看一些信息,请记住它不会更改它,然后在我们的情况下选择智慧,让我们使用Allst Allst,供应商i留给AWS,但这是您的标准和区域,这是我建议始终进行注册的另一个重要点,但是在您旁边,我的案子我将巴西放在巴西,我也选择了免费与免费,然后只需单击<<<<<< em>创建

create DB

完成此操作后,您将被重定向到此页面,在这里您有必要使用密钥创建用户。

criando usuario e senha para o mongo Atlas

apits这是将IP放置到群集连接的必要集群。

Adicionando seu IP ao cluster

一旦是,您已经创建了群集来连接API。

overview database

为此,我们需要一些将添加到环境中的数据有所不同,以与Mongo Atlas连接。单击连接时,将打开以下选项:

connect Mongo Atlas

您将选择选项驱动程序并将打开此新窗口。

connect Mongo Atlas com a API

在此窗口中,您将复制图像中选择的整行,请记住是您应用程序的明智数据为了访问您的群集,所有这些都将在您的环境中,我将在这里对环境变体进行取样,正在通过银行变量进行修改。

variaveis de ambiente

您的.env文件,应该是这种方式,现在在我们的 db文件中我们将与创建的mongo atlas建立联系。

import mongoose from "mongoose";
import { config as dotenvConfig } from "dotenv";
dotenvConfig();

export async function connect() {
  const baseUrl = `mongodb+srv://${process.env.MONGODB_USER}:${process.env.MONGODB_PASSWORD}@${process.env.MONGODB_CLUSTER_URL}/${process.env.MONGODB_DATABASE}`;
  try {
    const options: any = {};
    options.useNewUrlParser = true;
    options.useUnifiedTopology = true;
    await mongoose.connect(baseUrl, options);
    console.log("MongoDB connected sucess");
  } catch (error) {
    console.error(error);
  }
}

完成此操作后,我们已经通过创建数据库的呼叫,从我们的座右铭 connect ,后来将在我们的 server <>中调用,以将我们的数据库与我们的数据库连接应用程序。

现在,让我们创建我们的存储库,负责处理数据访问层。它提供了有关如何存储和恢复数据的抽象。主要目的是隔离存储存储的其余等待,使存储机构的交换或更新更加狂热,而不会影响系统的其余部分,因此我们将在这里创建我们的Bãês。创建,更新和删除整体。

import toDo, { toDo as toDoModel } from "../model/toDo";

class ToDoRepository {
  async getAllToDos(): Promise<toDoModel[]> {
    return toDo.find();
  }

  async createToDo(toDoData: Partial<toDoModel>): Promise<toDoModel> {
    return toDo.create(toDoData);
  }

  async updateToDoData(
    toDoId: string,
    updateData: Partial<toDoModel>
  ): Promise<toDoModel | null> {
    return toDo.findByIdAndUpdate(toDoId, updateData, { new: true });
  }

  async deleteToDo(toDoId: string): Promise<void> {
    await toDo.findByIdAndDelete(toDoId);
  }
}

export default new ToDoRepository();

我创建了一个用Crud的Crud创建了一个类,最后导出了一个类实例,用于在我的 service 中使用,我现在将创建,我也可以将另一个范式用作功能,por©我在这个项目中选择使用类范式,以下是我们现在创建我们的服务。

在我们的服务中,这是实施商业业务的停机时间,我们将其称为在存储库中创建的妈妈。

import toDoRepository from "../repository";
import { toDo } from "../model/toDo";

class ToDoService {
  async getAllToDos(): Promise<toDo[]> {
    return toDoRepository.getAllToDos();
  }

  async createToDo(toDoData: Partial<toDo>): Promise<toDo> {
    return toDoRepository.createToDo(toDoData);
  }

  async updateToDo(
    toDoId: string,
    updateData: Partial<toDo>
  ): Promise<toDo | null> {
    return toDoRepository.updateToDoData(toDoId, updateData);
  }

  async deleteToDo(toDoId: string): Promise<void> {
    return toDoRepository.deleteToDo(toDoId);
  }
}

export default new ToDoService();

已经使用我们的存储库 service 创建的以及创建我们的 Controller 的回合,而随着请求之间的中间享受和系统的其余部分。将收到请求,处理必要数据,与适当服务进行交互的人,并确定必须向用户呈现哪些愿景(或离开)。为此,我们现在将在这里创建我们的基本原始,如下所示。

import { Request, Response } from "express";
import toDoService from "../service";

class ToDoController {
  async getAllToDos(req: Request, res: Response): Promise<void> {
    try {
      const toDos = await toDoService.getAllToDos();
      res.json(toDos);
    } catch (error) {
      res.status(500).json({ error: "Error fetching toDos" });
    }
  }

  async createToDo(req: Request, res: Response): Promise<void> {
    const { text } = req.body;

    try {
      const newToDo = await toDoService.createToDo({ text });
      res.status(201).json(newToDo);
    } catch (error) {
      res.status(500).json({ error: "Error creating toDo" });
    }
  }

  async updateToDo(req: Request, res: Response): Promise<void> {
    const { toDoId } = req.params;
    const { completed } = req.body;

    try {
      const updatedToDo = await toDoService.updateToDo(toDoId, { completed });
      res.json(updatedToDo);
    } catch (error) {
      res.status(500).json({ error: "Error updating toDo" });
    }
  }

  async deleteToDo(req: Request, res: Response): Promise<void> {
    const { toDoId } = req.params;

    try {
      await toDoService.deleteToDo(toDoId);
      res.status(204).send();
    } catch (error) {
      res.status(500).json({ error: "Error deleting toDo" });
    }
  }
}

export default new ToDoController();

为了使其更加有组织,我使用了一些状态代码http ,以便我们的阵线可以对待这些信息。

现在,要更好地组织我们的应用程序,让我们创建我们的 douts ,我们的控制器呼叫将在哪里。

import express from "express";
import toDoController from "../controller";

const router = express.Router();

router.get("/toDos", toDoController.getAllToDos);
router.post("/toDos", toDoController.createToDo);
router.put("/toDos/:toDoId", toDoController.updateToDo);
router.delete("/toDos/:toDoId", toDoController.deleteToDo);

export default router;

因此,使用Mern的Express.js,我们可以使用Koud7创建一个称为路由器的路由器。路由器允许您分别定义路由以模块化代码并组织应用程序的不同部分。

现在我们需要创建我们的 server ,这将是我们拨打门并运行它的应用程序的终点。

但是,在此之前,我们将安装两个最后一个库以使生活更轻松,首先让我们安装。

npm install cors

这将来会解决可能的头痛, cors 可以在浏览器中处理相同的oriigin polycy),并允许服务器授予许可证,以便从特定域中的资源从另一个领域。尤其是当您构建API时,您将被不同的起源访问。确保适当地配置为您的安全需求和身份验证,在我们的情况下,这已经解决了。

不久之后,我们将安装此。

npm install -g nodemon

option -g 表示您正在系统上全球安装软件包,这意味着 nodemon 都可以在任何文件夹中的任何项目中使用。<<<<<<<<<<<<<<<<< /p>

o nodemon 是一种工具,可帮助使用Node.js开发应用程序,每次修改项目文件时都会自动重新启动服务器。这尤其是在开发中,因为它允许您立即看到更改,而无需每次手动重新启动服务器。

import express from "express";
import cors from "cors";
import { connect } from "./config/db";
import toDoRoutes from "./routes";

const app = express();
const PORT = process.env.PORT || 3001;

app.use(cors());
app.use(express.json());

connect();

app.use(toDoRoutes);

app.listen(PORT, () => {
  console.log(`Server is running on port ${PORT}`);
});

最后,在其案例 package.json main 中更改端点并不忘记,该 由standard index.js 用于我们的情况< em> server.ts ,然后将此命令添加到我们的软件包。json到您的脚本:

“start”: “nodemon src/server.ts”

在此执行此命令之后运行我们的API。

npm start

如果您遵循所有教程,则您的API将运行并以这种方式连接到您的数据库。

API rodando

现在让我们回到前端的应用程序,我们放手,让我们测试我们的功能。

如果您遵循所有内容©这里,我相信它可以完美地工作,只需将API服务器与API Server保持如此连接,然后将您的应用程序运行到端口3000,您会看到类似的东西,已经可以添加和添加和删除您的全部。

Aplicação Finalizada

,您还可以通过这种方式在Mongo Atlas的数​​据库中看到所有保存的东西。

RO DOs salvos no Mongo Atlas

好吧,这已经完成了,我们使用了基于堆栈Mern构建的完全功能应用程序,使用首字母缩写的所有技术。

我没有专注于风格化,或者甚至没有在我们的API的安全部分以及测试中,我只是对母亲为客户的Postman等客户进行了测试,如果所有路线正常工作,我认为这是另一个文章的约束,但可以随意使用此示例作为项目的基础并在您的港口中发布,例如,Evolve可以将API OVEL WEF api登录,每个用户都有自己的实践,所有用户都保存在单独的银行,最后是继续此应用程序的想法。

在将来的另一篇文章中,我将每次连接服务器连接时必须在本地主机中使用它的后端应用程序,以将其部署到本地主机中。

包括£o

Stack Mern为开发现代和烫伤Web应用程序提供了强大的环境。它结合了mongodb的灵活性,express.js的敏捷性,反应的相互作用和node.js的效率。在提出学习和复杂性挑战的同时,MERN堆栈的好处在需要动态接口,可扩展性和标签开发的项目中很明显。在研究此堆栈时,开发人员将有足够的能力面对网络开发的挑战和需求,从业务的前端投射端到端应用程序,从逻辑上讲,每个项目都有其规范,无法成为银色始终将其用于所有事物的子弹,因为它自己和缺点,其在项目中学习或使用它的批评者。