Обмен мгновенными сообщениями — одна из самых важных функций, которые мы используем каждый день. Используя только JavaScript и помощь socket.io, узнайте вместе со мной, как создать простое веб-приложение для чата!
Оглавление
- "Введение"
- Ступеньки
2а. Сервер
Бонус! CORS
2б. Клиент
Бонус! Использование идентификатора пользователя - "Заключение"
- "Хочу больше? Другие ресурсы, которые стоит проверить!»
Введение 🧑🍳
Завершив 2022 год и имея за плечами более года опыта работы инженером-программистом, я начал 2023 год с размышлений и воспоминаний о своем пребывании в буткемпе. В частности, когда это было время проекта и все удовольствие (и стресс 😅) от придумывания и выполнения проекта. Это заставило меня вспомнить, как многие из нас хотели включить функцию обмена мгновенными сообщениями, но в то время она казалась слишком сложной с точки зрения знаний, навыков и, честно говоря, времени на создание. Именно тогда я решил начать этот год с изучения веб-сокетов и того, как их создать за относительно короткое время.
Цель этой статьи — помочь вам создать простое приложение для чата с использованием Express, React и Socket.io. Перейдите к следующему разделу для шагов, обратитесь к Заключение, если вы визуальный человек и вам нужно увидеть все, прежде чем разбивать его, или если вы хотите узнать больше о веб-сокетах и socket.io, вот видео с боевого корабля:
Шаги 🥖
Чтобы начать сборку, нам нужно сначала убедиться, что у нас установлен узел, а также создать новую папку для этого проекта. За подробностями вы можете обратиться к моей другой статье «Как настроить простой API с узлом и экспрессом», в противном случае мы готовы перейти за вами cd
в новую папку проекта.
Сервер 🍅
Теперь, когда мы находимся в папке проекта, давайте начнем сборку с сервера.
- Создайте новую папку для сервера:
mkdir server
2. Инициализируйте этот проект как проект узла:
npm init -y
3. Установите эти пакеты:
npm install express --save npm install --save-dev nodemon npm install socket.io
4. Обновите сценарии package.json с помощью:
start: “nodemon index.js”
5. В index.js добавляем следующее (взято из документации socket.io- Инициализация и обработка CORS)
const express = require("express"); const { createServer } = require("http"); const { Server } = require("socket.io"); const app = express(); const httpServer = createServer(app); const io = new Server(httpServer, { cors: { origin: "*", }, }); io.on("connection", (socket) => { // ... }); httpServer.listen(8080);
Мы включаем внутрь cors, origin: “*”,
, чтобы разрешить запросы из любого места и упростить этот шаг, так как это больше для изучения того, как создать базовое приложение для чата. Однако вы можете указать порт (например: http://localhost:8080'), если хотите. Чтобы узнать больше о Cors, посмотрите это видео с Fireship ниже:
6. Добавьте другие события после подключения (примеры ниже)
io.on("connection", (socket) => { console.log("user connected"); socket.on("send message", (body) => { io.emit("message", body); }); socket.on("disconnect", () => { console.log("user disconnected"); }); });
Что приятно в том, как работает socket.io, так это то, что он вдохновлен Node.js EventEmitter. Другими словами, socket.io похож на то, как вы можете добавить прослушиватель событий onClick
к кнопке; одна сторона генерирует событие, а другая сторона может иметь для него прослушиватель. Примеры событий можно найти в этой шпаргалке на сайте socket.io, однако вы также можете создавать свои собственные события!
Чтобы еще больше продемонстрировать, как работают события, вот пример, взятый из socket.io, где hello
— это событие:
// Server io.on("connection", (socket) => { socket.emit("hello", "world"); }); // Client socket.on("hello", (arg) => { console.log(arg); // world });
Клиент 🥑
Теперь, когда сервер настроен и работает, давайте перейдем к клиенту, вернувшись в главный каталог проекта с помощью cd ..
.
- Создайте интерфейс React:
npx create-react-app <app-name>
2. Установите клиент пакета socket.io:
npm install socket.io-client
3. Удалите StrictMode в App/index.js
, чтобы компоненты не отображались дважды, что приводит к множественным соединениям при обновлении.
4. Добавьте эти импорты в App.js
import { useRef, useState, useEffect } from “react”; const { io } = require("socket.io-client");
5. Создайте ссылку на сокет
const socketRef = useRef();
6. Добавьте useEffect
для запуска при загрузке страницы и подключения к серверу.
useEffect(() => { // or whichever port you set on the server socketRef.current = io.connect("http://localhost:8080"); socketRef.current.on("connected", (message) => { receivedMessage(message); }); socketRef.current.on("message", (message) => { receivedMessage(message); }); socketRef.current.on("disconnected", (message) => { receivedMessage(message); }); return () => socketRef.current.disconnect(); }, []);
7. Чтобы получить ввод пользователя для сообщения, которое он хочет отправить, давайте добавим простую форму:
const [message, setMessage] = useState(“”); const handleInputChange = (event) => { setMessage(event.target.value); }; return( <div className="App"> <form onSubmit={sendMessage}> <input type="text" value={message} onChange={handleInputChange} /> <input type="submit" /> </form> </div> )
8. Чтобы на самом деле отправить информацию на сервер от клиента, нам нужно сделать socketRef.current.emit(<eventName>, message);
const sendMessage = (event) => { event.preventDefault(); socketRef.current.emit("send message", message); setMessage(""); };
9. Наконец, чтобы отобразить сообщения, которые получает клиент:
const [messages, setMessages] = useState([]);: // this function is used within the useEffect from step 6 with the event listeners const receivedMessage = (message) => { setMessages((prevMessages) => [...prevMessages, message]); }; return( <div className="App"> {messages.map((message, index) => { return <p key={index}>{message}</p>; })} </div> )
Бонус! Использование идентификатора пользователя
Как бы ни была важна отправка сообщений, не менее важно знать, кто и какое сообщение отправил, особенно по мере увеличения количества людей в чате. В этом нам снова помогает Socket.io, так как при каждом новом подключении присваивается случайный 20-символьный идентификатор, который синхронизируется со значением на стороне сервера. Теперь мы можем обновить наш код следующим образом:
const [userId, setUserId] = useState(""); useEffect(() => { socketRef.current.on("connect", () => { receivedMessage("Welcome new user!"); setUserId(socketRef.current.id); }); ... } const sendMessage = (event) => { event.preventDefault(); const messageObj = { userId, message, }; socketRef.current.emit("send message", messageObj); setMessage(""); }; return( <div className="App"> <p>My userId is: {userId}</p> </div> )
Вывод 😋
Поздравляем, теперь у вас должно быть работающее веб-приложение чата! Для проверки вы можете открыть две, три или более разных вкладок в своем браузере для любого порта, на который настроен внешний интерфейс (например, localhost: 3000). Тем не менее, поскольку мы не добавляли никаких стилей, пользовательский интерфейс не самый интуитивно понятный, поэтому я рекомендую вам использовать этот аспект самостоятельно. Чтобы помочь вам начать работу, подумайте, как сделать так, чтобы пользователю было легче узнать, какое сообщение кому принадлежит.
Если вы хотите сравнить и посмотреть, как должны выглядеть полные основные файлы сервера и клиента:
// Server/index.js const express = require("express"); const { createServer } = require("http"); const { Server } = require("socket.io"); const app = express(); const httpServer = createServer(app); const io = new Server(httpServer, { cors: { origin: "*", // or "http://localhost:3000" }, }); io.on("connection", (socket) => { console.log(`User ${socket.id} joined the chat`); // inform everyone in chat a new user joined io.emit("connected", `User ${socket.id} joined the chat`); socket.on("send message", (body) => { const { userId, message } = body; io.emit("message", `User ${userId} typed ${message}`); }); socket.on("disconnect", () => { console.log(`User ${socket.id} left the chat`); io.emit("disconnected", `User ${socket.id} left the chat`); }); }); httpServer.listen(8080, () => { console.log("server is running on 8080"); }); // Client/src/App.js import "./App.css"; import { useRef, useState, useEffect } from "react"; const { io } = require("socket.io-client"); function App() { const [messages, setMessages] = useState([]); const [message, setMessage] = useState(""); const [userId, setUserId] = useState(""); const socketRef = useRef(); useEffect(() => { // or whichever port you set on the server socketRef.current = io.connect("http://localhost:8080"); socketRef.current.on("connect", () => { receivedMessage("Welcome new user!"); setUserId(socketRef.current.id); }); socketRef.current.on("connected", (message) => { receivedMessage(message); }); socketRef.current.on("message", (message) => { receivedMessage(message); }); socketRef.current.on("disconnected", (message) => { receivedMessage(message); }); return () => socketRef.current.disconnect(); }, []); const receivedMessage = (message) => { setMessages((prevMessages) => [...prevMessages, message]); }; const sendMessage = (event) => { event.preventDefault(); const messageObj = { userId, message, }; socketRef.current.emit("send message", messageObj); setMessage(""); }; const handleInputChange = (event) => { setMessage(event.target.value); }; return ( <div className="App"> <div> {messages.map((message, index) => { return <p key={index}>{message}</p>; })} </div> <div> <form onSubmit={sendMessage}> <input type="text" value={message} onChange={handleInputChange} /> <input type="submit" /> </form> </div> <p>My userId is: {userId}</p> </div> ); } export default App;
Большое спасибо за прочтение ❤️ Надеюсь, это помогло вам начать работу над новым проектом и/или вы можете включить часть мгновенных сообщений в один из ваших текущих проектов!
Если вам понравилось это читать, ознакомьтесь с другими моими статьями! Хорошим местом для начала является Как настроить простой API с Node.js и Express, Запросы на выборку и действия контроллера: подключение интерфейса к серверу или Все о рендеринге: клиент и Сервер».
Хотите больше? Другие ресурсы, чтобы проверить! 💾
Дополнительные материалы на PlainEnglish.io. Подпишитесь на нашу бесплатную еженедельную рассылку новостей. Подпишитесь на нас в Twitter, LinkedIn, YouTube и Discord .
Заинтересованы в масштабировании запуска вашего программного обеспечения? Ознакомьтесь с разделом Схема.