+2

Xây dựng ứng dụng chat thời gian thực với Socket.io, Express, React.js và Chakra UI

Nếu các bạn đã đọc qua bài viết của tôi: Hướng dẫn chi tiết cách tự tạo Chatbot React đơn giản từ A đến Z; thì trong bài viết này tôi sẽ giới thiệu cho các bạn một cách xây dựng ứng dụng chat thời gian thực vô cùng hữu ích với React, Socket.io, Chakra UI và Express. Hãy cùng theo dõi nhé.

Trong bài viết này, chúng ta sẽ cùng nhau xây dựng một ứng dụng chat thời gian thực sử dụng Socket.io để giao tiếp hai chiều, Express.js cho máy chủ, React.js cho giao diện người dùng và Chakra UI cho việc tạo kiểu. Chúng ta sẽ thiết lập dự án bằng Vite để phát triển nhanh chóng.

Các tính năng chính của ứng dụng Chat:

  • Chat dựa trên ID người dùng: Một userId ngẫu nhiên được tạo và lưu trữ trong bộ nhớ phiên.
  • Hiển thị tin nhắn: Tin nhắn của chúng ta xuất hiện ở bên trái và tin nhắn của người khác xuất hiện ở bên phải, mỗi tin nhắn đều có một biểu tượng.

Chúng ta cùng bắt đầu theo từng bước nhé!

Thiết lập dự án

Đầu tiên, hãy tạo một thư mục bao quanh chat-app nơi chứa front-end và back-end của chúng ta:

mkdir chat-app
cd chat-app

Thiết lập Backend: Express.js với Socket.io

Đầu tiên, tạo một thư mục cho backend của bạn và khởi tạo nó bằng npm init -y:

mkdir chat-backend
cd chat-backend
npm init -y

Bây giờ hãy cài đặt các gói cần thiết:

npm install express socket.io

Tạo cấu trúc tệp sau cho backend:

chat-backend/
│
├── server.js
└── package.json

server.js - Express và Socket.io Dưới đây là cách thiết lập máy chủ Express với Socket.io:

const express = require('express');
const http = require('http');
const { Server } = require('socket.io');

const app = express();
const server = http.createServer(app);
const io = new Server(server, {
  cors: {
    origin: 'http://localhost:5173',
    methods: ['GET', 'POST']
  }
});

io.on('connection', (socket) => {
  console.log('A user connected:', socket.id);

  socket.on('sendMessage', (message) => {
    io.emit('receiveMessage', message);
  });

  socket.on('disconnect', () => {
    console.log('A user disconnected');
  });
});

server.listen(4000, () => {
  console.log('Server listening on port 4000');
});

Đoạn mã này tạo một máy chủ Express lắng nghe trên cổng 4000 và thiết lập Socket.io để xử lý giao tiếp thời gian thực. Khi người dùng gửi tin nhắn (sự kiện sendMessage), nó sẽ được phát đến tất cả các máy khách được kết nối.

Thiết lập Frontend: Vite với React và Chakra UI

Tạo một dự án Vite React và làm theo các ảnh chụp bên dưới (tạo dự án trong chat-app chứ không phải trong chat-backend):

npm create vite@latest

image.png

image.png

image.png

Điều hướng vào thư mục dự án và cài đặt các dependency cần thiết:

cd chat-frontend
npm install socket.io-client @chakra-ui/react @emotion/react @emotion/styled framer-motion

Bây giờ, hãy tạo một cấu trúc cơ bản cho ứng dụng chat của chúng ta.

Xây dựng giao diện người dùng cho ứng dụng Chat

Cấu trúc cho frontend sẽ như sau:

chat-frontend/
│
├── src/
│   ├── components/
│   │   └── ChatBox.jsx
│   ├── App.jsx
│   └── main.jsx
├── index.html
└── package.json

App.jsx Trong App.jsx, thiết lập Chakra UI và hiển thị component ChatBox:

import { ChakraProvider, Box, Heading } from "@chakra-ui/react";
import ChatBox from "./components/ChatBox";

function App() {
  return (
    <ChakraProvider>
      <Box p={5}>
        <Heading as="h1" mb={6}>
          Real-Time Chat
        </Heading>
        <ChatBox />
      </Box>
    </ChakraProvider>
  );
}

export default App;

ChatBox.jsx Đây là nơi chứa logic chính của chat. Chúng ta sẽ sử dụng Socket.io để lắng nghe tin nhắn và xử lý các cập nhật theo thời gian thực. Một userId ngẫu nhiên được tạo và lưu trữ trong sessionStorage, và giao diện người dùng chat được xây dựng bằng cách sử dụng Chakra UI.

import React, { useState, useEffect } from "react";
import { Box, Input, Button, HStack, VStack, Text, Avatar } from "@chakra-ui/react";
import { io } from "socket.io-client";

const socket = io("http://localhost:4000");

const ChatBox = () => {
  const [messages, setMessages] = useState([]);
  const [input, setInput] = useState("");
  const [userId, setUserId] = useState(null);

  useEffect(() => {
    // Generate or get userId from session storage
    let storedUserId = sessionStorage.getItem("userId");
    if (!storedUserId) {
      storedUserId = Math.random().toString(36).substring(7);
      sessionStorage.setItem("userId", storedUserId);
    }
    setUserId(storedUserId);

    // Listen for messages
    socket.on("receiveMessage", (message) => {
      setMessages((prevMessages) => [...prevMessages, message]);
    });

    return () => {
      socket.off("receiveMessage");
    };
  }, []);

  const sendMessage = () => {
    if (input.trim()) {
      const message = {
        userId,
        text: input,
      };
      socket.emit("sendMessage", message);
    //   setMessages((prevMessages) => [...prevMessages, message]);
      setInput("");
    }
  };

  return (
    <VStack spacing={4} align="stretch">
      <Box h="400px" p={4} borderWidth={1} borderRadius="lg" overflowY="auto">
        {messages.map((msg, index) => (
          <HStack key={index} justify={msg.userId === userId ? "flex-start" : "flex-end"}>
            {msg.userId === userId && <Avatar name="Me" />}
            <Box
              bg={msg.userId === userId ? "blue.100" : "green.100"}
              p={3}
              borderRadius="lg"
              maxW="70%"
            >
              <Text>{msg.text}</Text>
            </Box>
            {msg.userId !== userId && <Avatar name="Other" />}
          </HStack>
        ))}
      </Box>

      <HStack>
        <Input
          value={input}
          onChange={(e) => setInput(e.target.value)}
          placeholder="Type a message"
        />
        <Button onClick={sendMessage} colorScheme="teal">
          Send
        </Button>
      </HStack>
    </VStack>
  );
};

export default ChatBox;

Cách thức hoạt động:

  • userId ngẫu nhiên: Chúng ta tạo một chuỗi ngẫu nhiên làm userId và lưu trữ nó trong sessionStorage. Điều này đảm bảo rằng ngay cả khi bạn tải lại trang, bạn sẽ vẫn giữ nguyên userId cho phiên đó.
  • Socket.io để nhắn tin: Ứng dụng lắng nghe các sự kiện receiveMessage từ máy chủ và hiển thị các tin nhắn đến. Khi người dùng gửi tin nhắn, nó sẽ được phát đi qua Socket.io và giao diện người dùng được cập nhật theo thời gian thực.
  • Tạo kiểu Chakra UI: Tin nhắn được hiển thị trong một hộp, với tin nhắn của chúng ta được căn chỉnh sang trái (với nền màu xanh lam) và tin nhắn của người khác được căn chỉnh sang phải (nền màu xanh lục). Mỗi tin nhắn cũng có một avatar cho giao diện chat đơn giản, được cá nhân hóa.

Chạy ứng dụng

Khởi động backend:

cd chat-backend
node server.js

Khởi động frontend:

cd chat-frontend
npm run dev

Bây giờ, hãy mở http://localhost:5173 trong nhiều cửa sổ trình duyệt để kiểm tra chức năng chat thời gian thực. Bạn sẽ thấy tin nhắn của mỗi người dùng được hiển thị với userId duy nhất của họ.

Bạn đã xây dựng thành công một ứng dụng chat thời gian thực bằng cách sử dụng Socket.io, Express, React.js và Chakra UI, với dự án được thiết lập thông qua Vite!

Ứng dụng này thể hiện sức mạnh của Socket.io đối với giao tiếp thời gian thực và Chakra UI cho một giao diện sạch sẽ, phản hồi nhanh.

Bạn có thể mở rộng dự án này bằng cách thêm các tính năng như phòng chat, lưu trữ tin nhắn và xác thực người dùng.

Cảm ơn các bạn đã theo dõi, chúc các bạn làm việc vui vẻ!


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí