Kaip sukurti programą realiuoju laiku naudojant „Socket.io“, „React“, „Node“ ir „MongoDB“

Ar kada susimąstėte, kaip kuriamos programos realiuoju laiku? Ar kada pastebėjote realaus laiko programų svarbą ir naudojimo atvejus?

Jei jums įdomu aukščiau pateikti klausimai ir jums reikia atsakymo, šis tinklaraščio įrašas skirtas jums.

Pirmiausia nustatykime kelis naudojimo atvejus, kuriems reikia programų realiuoju laiku:

  1. Gaunate savo kabinos vietos atnaujinimus kabinos rezervavimo programos žemėlapyje.
  2. Akimirksniu gaukite naujus pranešimus mėgstamoje pokalbių programoje.
  3. Maisto užsakymo informacijos atnaujinimas jūsų mėgstamiausio restorano virtuvėje.

Tai visi įprasti mūsų kasdienio gyvenimo scenarijai, kai mes negalime toleruoti vėlavimo atnaujinti informacijos, todėl reikia bendravimo realiuoju laiku.

Technologijos, kurias galima naudoti bendraujant realiuoju laiku, yra šios:

  1. Trumpas apklausa : AJAX, sukuria intensyvų srautą.
  2. Ilgas apklausa : kaip ir AJAX, tačiau serveris palaiko atsakymą, kol jis turi atnaujinimą. Gavęs klientą, jis išsiunčia kitą užklausą ir jam reikia papildomų antraščių, kad būtų galima pereiti pirmyn ir atgal, sukeliant papildomą pridėtinę sumą.
  3. Tinklo lizdai : leidžia atverti interaktyvų ryšį tarp kliento ir serverio. Galima siųsti užklausą į serverį ir gauti įvykių atsakymus, netikrinant serverio atsakymo, todėl interneto lizdai yra geriausias pasirinkimas mūsų naudojimo atveju.

Išsamesnę informaciją apie minėtas tris technologijas galite perskaityti čia.

Mes išmoksime sukurti realaus laiko programą, apimančią šį scenarijų.

Įsivaizduokite, kad sėdite mėgstamame restorane ir turite skaitmeninį meniu. Pateikiate užsakymą ir virtuvė atnaujinama atsižvelgiant į jūsų užsakymą realiu laiku. Kai virtuvė bus baigta pagal užsakymą, jie taip pat ją atnaujins realiuoju laiku.

Išsamios savybės:

  1. Pateikti užsakymą : sąsaja, kad pasirinktumėte maisto kiekį ir pateiktų užsakymą į virtuvę.
  2. Virtuvė : sąsaja, kurią galima atidaryti keliose virtuvėse, o virėjai ir virėjai realiuoju laiku atnaujina bendrą sukurtų užsakymų skaičių ir numatomą maisto produktų kiekį, suteikdami jiems galimybę jį atnaujinti. Taip pat turi funkciją atsisiųsti ataskaitą „Excel“ lapo forma.
  3. Keisti numatomą: sąsaja atnaujinti numatomą maisto produktų kiekį.

Tiesioginę šio scenarijaus demonstraciją galite rasti čia.

Norėdami geriau suprasti, atidarykite jį skirtinguose skirtukuose / įrenginiuose tuo pačiu metu, kad pamatytumėte, kaip duomenys keičiasi realiuoju laiku.

Šaltinio kodas yra čia. Nedvejodami pasigaminkite ką nors novatoriško / naudingo.

Taigi pradėkime.

Technologija:

„Frontend“ : „React.js“, „Reactstrap“, „Socket.io“

Programinė įranga : „Node.js“ („Express“), „MongoDB“, „Socket.io“

Aplanko struktūra:

/* Go to the root directory in the source code and find out the below-mentioned files. This architecture helps in creating a big modular App. */ backend-my-app/ /* Backend code of the app */ server.js /* Socket and backend code resides here*/ build/ /* Optional for deployment of Frontend Build */ package.json /* Backend dependency */ ... public/ src/ /* Frontend Sourcecode */ global/ /* Components getting used everywhere */ header.css header.js main/ Kitchen.js PlaceOrder.js UpdatePredicted.js App.js /* Routing logic and component assembly part */ package.json /* Frontend dependency */ ............

Šaltinio kodo paaiškinimas:

Frontendas:

git clone //github.com/honey93/OrderKitchen.git cd OrderKitchen npm install npm start

Panaudotos pakuotės:

  1. „Reactstrap“: lengvai naudojami „bootstrap4“ komponentai
  2. „Socket.io“: „Socket.io“ yra biblioteka, leidžianti realiuoju laiku, dvikrypčiu ir įvykiais pagrįstą ryšį tarp naršyklės ir serverio.
  3. reaguoti-html-table-to-excel: Pateikia kliento pusėje generuojamą „Excel“ (.xls) failą iš HTML lentelės elemento.
  4. react-router-dom: DOM susiejimai, skirti reaguoti maršrutizatoriui. Jį sudaro daugybė svarbių komponentų, tokių kaip „BrowserRouter“, naudojamas, kai serveris tvarko dinamines užklausas, „Switch“, „Route“ ir kt.

Programos komponentas

Kelias : src / App.js

Šiame komponente yra pagrindinė „Frontend“ nukreipimo logika. Šis failas naudojamas naršyklės maršrutizatoriaus modulyje esančiame src / index.js. Žemiau pateiktas kodas rodo vieną iš būdų, kaip išlaikyti jūsų programą modulinę.

import React, { Component } from "react"; import "./App.css"; import { Header } from "./global/header"; import { Switch, Route } from "react-router-dom"; import PlaceOrder from "./main/PlaceOrder"; import UpdatePredicted from "./main/UpdatePredicted"; import Kitchen from "./main/Kitchen"; /*The  component is the main part of React Router. Anywhere that you want to only render content based on the location’s pathname, you should use a  element. */ /* The Route component expects a path prop, which is a string that describes the pathname that the route matches */ /* The  will iterate over routes and only render the first one that matches the current pathname */ class App extends Component { render() { return ( ); } } export default App;

Antraštės komponentas

Kelias : src / global / header.js

Šis komponentas bus įprastas ir naudojamas visuose skyriuose, pvz., „Pateikti užsakymą“, „Numatomas pakeitimas“, „Virtuvė“. Šis metodas padeda išvengti kodo dubliavimo ir išlaiko programą modulinę.

import React, { Component } from "react"; import { NavLink } from "react-router-dom"; import socketIOClient from "socket.io-client"; import "./header.css"; // The Header creates links that can be used to navigate // between routes. var socket; class Header extends Component { /* Creating a Socket client and exporting it at the end to be used across the Place Order, Kitchen, etc components*/ constructor() { super(); this.state = { endpoint: '//localhost:3001/' }; socket = socketIOClient(this.state.endpoint); } render() { return (   
    
  • Place Order
  • Change Predicted
  • Kitchen
); } } export { Header, socket };

Virtuvės komponentas

Kelias : src / main / Kitchen.js

Virtuvės ekrano vartotojo sąsajos logika ir HTML kodas yra šiame komponente:

import React, { Component } from "react"; import { Button, Table, Container } from "reactstrap"; import { socket } from "../global/header"; import ReactHTMLTableToExcel from "react-html-table-to-excel"; class Kitchen extends Component { constructor() { super(); this.state = { food_data: [] // this is where we are connecting to with sockets, }; } getData = foodItems => { console.log(foodItems); this.setState({ food_data: foodItems }); }; changeData = () => socket.emit("initial_data"); /*As soon as the component gets mounted ie in componentDidMount method, firing the initial_data event to get the data to initialize the Kitchen Dashboard */ /* Adding change_data listener for listening to any changes made by Place Order and Predicted Order components*/ componentDidMount() { var state_current = this; socket.emit("initial_data"); socket.on("get_data", this.getData); socket.on("change_data", this.changeData); } /* Removing the listener before unmounting the component in order to avoid addition of multiple listener at the time revisit*/ componentWillUnmount() { socket.off("get_data"); socket.off("change_data"); } /* When Done gets clicked, this function is called and mark_done event gets emitted which gets listened on the backend explained later on*/ markDone = id => { // console.log(predicted_details); socket.emit("mark_done", id); }; getFoodData() { return this.state.food_data.map(food => { return (  {food.name}  {food.ordQty}  {food.prodQty}  {food.predQty}   this.markDone(food._id)}>Done  ); }); } render() { return (  

Kitchen Area

{this.getFoodData()}
Name Quantity Created Till Now Predicted Status
); } } export default Kitchen;

Pateikite užsakymo komponentą

Path: src/main/PlaceOrder.js

import React, { Component } from "react"; import { Button, Table, Container } from "reactstrap"; import { socket } from "../global/header"; class PlaceOrder extends Component { constructor() { super(); this.state = { food_data: [] // this is where we are connecting to with sockets, }; } getData = foodItems => { console.log(foodItems); foodItems = foodItems.map(food => { food.order = 0; return food; }); this.setState({ food_data: foodItems }); }; componentDidMount() { socket.emit("initial_data"); var state_current = this; socket.on("get_data", state_current.getData); } componentWillUnmount() { socket.off("get_data", this.getData); } //Function to place the order. sendOrder = id => { var order_details; this.state.food_data.map(food => { if (food._id == id) { order_details = food; } return food; }); console.log(order_details); socket.emit("putOrder", order_details); var new_array = this.state.food_data.map(food => { food.order = 0; return food; }); this.setState({ food_data: new_array }); }; // Changing the quantity in the state which is emitted to the backend at the time of placing the order. changeQuantity = (event, foodid) => { if (parseInt(event.target.value)  { if (food._id == foodid) { food.order = parseInt(event.target.value); } return food; }); this.setState({ food_data: new_array }); }; // To get the initial data getFoodData() { return this.state.food_data.map(food => { return (  {food.name}   this.changeQuantity(e, food._id)} value={food.order} type="number" placeholder="Quantity" />  this.sendOrder(food._id)}>Order  ); }); } render() { return (  

Order Menu

{this.getFoodData()}
Product Quantity Order
); } } export default PlaceOrder;

One more section called Update Predicted Path: src/main/UpdatePredicted.js similar to above section is there in the code repository.

Backend

Starting the Backend:

cd backend-my-app npm install node server.js

Packages used:

  1. Monk: A tiny layer that provides simple yet substantial usability improvements for MongoDB usage within Node.JS.
  2. Socket.io: Socket.io is a library that enables real-time, bidirectional and event-based communication between the browser and the server.

3. Express: Fast, minimalist web framework for node.

Main Code

Path: backend-my-app/server.js

const express = require("express"); const http = require("http"); const socketIO = require("socket.io"); // Connection string of MongoDb database hosted on Mlab or locally var connection_string = "**********"; // Collection name should be "FoodItems", only one collection as of now. // Document format should be as mentioned below, at least one such document: // { // "_id": { // "$oid": "5c0a1bdfe7179a6ca0844567" // }, // "name": "Veg Roll", // "predQty": 100, // "prodQty": 295, // "ordQty": 1 // } const db = require("monk")(connection_string); const collection_foodItems = db.get("FoodItems"); // our localhost port const port = process.env.PORT || 3000; const app = express(); // our server instance const server = http.createServer(app); // This creates our socket using the instance of the server const io = socketIO(server); io.on("connection", socket => { // console.log("New client connected" + socket.id); //console.log(socket); // Returning the initial data of food menu from FoodItems collection socket.on("initial_data", () => { collection_foodItems.find({}).then(docs => { io.sockets.emit("get_data", docs); }); }); // Placing the order, gets called from /src/main/PlaceOrder.js of Frontend socket.on("putOrder", order => { collection_foodItems .update({ _id: order._id }, { $inc: { ordQty: order.order } }) .then(updatedDoc => { // Emitting event to update the Kitchen opened across the devices with the realtime order values io.sockets.emit("change_data"); }); }); // Order completion, gets called from /src/main/Kitchen.js socket.on("mark_done", id => { collection_foodItems .update({ _id: id }, { $inc: { ordQty: -1, prodQty: 1 } }) .then(updatedDoc => { //Updating the different Kitchen area with the current Status. io.sockets.emit("change_data"); }); }); // Functionality to change the predicted quantity value, called from /src/main/UpdatePredicted.js socket.on("ChangePred", predicted_data => { collection_foodItems .update( { _id: predicted_data._id }, { $set: { predQty: predicted_data.predQty } } ) .then(updatedDoc => { // Socket event to update the Predicted quantity across the Kitchen io.sockets.emit("change_data"); }); }); // disconnect is fired when a client leaves the server socket.on("disconnect", () => { console.log("user disconnected"); }); }); /* Below mentioned steps are performed to return the Frontend build of create-react-app from build folder of backend Comment it out if running locally*/ app.use(express.static("build")); app.use("/kitchen", express.static("build")); app.use("/updatepredicted", express.static("build")); server.listen(port, () => console.log(`Listening on port ${port}`));

Database: MongoDB

Mlab: Database as a service for MongoDB

Collection Name: FoodItems

Dokumento formatas : „FoodItems“ kolekcijoje reikalingas bent vienas dokumentas, kurio formatas yra žemiau.

{ "name": "Veg Roll", // Food Name "predQty": 100, // Predicted Quantity "prodQty": 295, // Produced Quantity "ordQty": 1 // Total Order Quantity }

Tikimės, kad supratote, kaip sukurti modulinę realaus laiko programą naudojant populiarėjantį MERN kaminą. Jei radote naudingą plojimą žemiau, padovanokite žvaigždžių projekto repo ir pasidalykite su draugais.