Hướng dẫn tạo chức năng thông báo thời gian thực với Laravel và Reactjs

Hướng dẫn tạo chức năng thông báo thời gian thực với Laravel và Reactjs

Trong các ứng dụng web hiện nay thì phần thông báo đã trở thành một thành phần rất quan trọng trong hệ thống website hay ứng dụng web của chúng ta nó được ứng dụng để thông báo tới người dùng những thông báo theo thời gian thực giúp người dùng nắm bắt thông tin một cách nhanh nhất. Hôm nay tôi sẽ hướng dẫn các bạn làm chức năng thông báo theo thời gian thực bằng Laravel và Reactjs một cách đơn giản và nhanh nhất.

Để làm được chức năng này bằng Laravel và Reactjs thì chúng ta cần tới 1 thư viện đó là Pusher. Đây là thư viện giúp chúng ta xây dựng các ứng dựng realtime sử dụng web socket một cách đơn giản và nhanh nhất mà bạn không phải mất quá nhiều thời gian để có thể tạo cho mình một ứng dụng websocket.

Đầu tiên ta hãy chạy lệnh sau để cài đặt thư viện Pusher cho Laravel.

composer require pusher/pusher-php-server

Sau khi đã cài thư viện vào Laravel ta cần tạo một tài khoản trên trang chủ Pusher.com cách đăng ký khá dễ hoặc bạn có thể chọn đăng ký bằng tài khoản Google cũng được.

Sau khi đã đăng ký và đăng nhập thành công thì bạn nhấn Get started bên phần channel để bắt đầu tạo một kênh mới cho ứng dụng của bạn cách tạo rất đơn giản bạn chỉ việc nhập tên cho ứng dụng của bạn chọn ngôn ngữ fontend bạn sử dụng ở đây tôi dùng Laravel echo và ngôn ngữ phía backend bạn sử dụng ở đây là framework Laravel sau đó nhấn Create là bạn hệ thống sẽ tự tạo một channel cho bạn sử dụng.

thông tin channel pusher

thông tin channel pusher

Sau khi Pusher đã tạo channel cho bạn thì bạn quay lại dự án Laravel của mình tại file .env bạn chỉnh sửa các thông tin cấu hình pusher theo thông tin mà pusher đã cung cấp cho bạn. Ví dụ trong file .env của tôi, tôi sẽ cấu hình như sau:

BROADCAST_DRIVER=pusher
PUSHER_APP_ID=1123388
PUSHER_APP_KEY=a91bfcfd34b8817c5109
PUSHER_APP_SECRET=c3ab45cb41a4a0afa5cd
PUSHER_APP_CLUSTER=ap1

Xong chỉ cần như vậy là bạn đã cấu hình xong pusher cho dự án của mình rồi, tiếp theo bạn cần chạy lệnh artisan để tạo một event mới trong dự án của bạn ở đây tôi đang làm chức năng thông báo nên tôi sẽ chạy lệnh như sau:

php artisan make:event NoticeEvent

Sau khi chạy lệnh trên Laravel sẽ tạo cho chúng ta một file Event mới có tên là NoticeEvent và việc của chúng ta bây giờ là chỉnh sửa lại nó để có thể sử dụng Boardcast của Pusher.

Trong file đó bạn phảiimplements interfaceShouldBroadcastcủa thư viện Pusher server sau đó bạn hãy chú ý đến hai hàm quan trọng nhất trong file event này là hàmbroadcastOnvà hàmbroadcastAs.

Ở hàm broadcastOn thì bạn hãy điền tên channel mà bạn đã tạo trên tài khoản pusher của bạn vô và broadcastAs thì bạn hãy điền tên event mà bạn đã tạo trên tài khoản pusher của mình vô. Như file NoticeEvent của tôi sẽ như thế này.

<?php

namespace App\Events;

use Illuminate\Broadcasting\Channel;

use Illuminate\Broadcasting\InteractsWithSockets;

use Illuminate\Broadcasting\PresenceChannel;

use Illuminate\Broadcasting\PrivateChannel;

use Illuminate\Contracts\Broadcasting\ShouldBroadcast;

use Illuminate\Foundation\Events\Dispatchable;

use Illuminate\Queue\SerializesModels;

class NoticeEvent implements ShouldBroadcast

{

    use Dispatchable, InteractsWithSockets, SerializesModels;

    public $message;

    public function __construct($message)

    {

        $this->message = $message;

    }

    public function broadcastOn()

    {

        return ['my-channel'];

    }

    public function broadcastAs()

    {

        return 'my-event';

    }

}
Như vậy là xong chúng ta đã viết file xong file event cho pusher rồi tiếp theo chúng ta sẽ làm phần gửi thông báo từ server xuống client khi có các thông báo được gửi đi.
Trong database tôi đã xây dựng một bảng Notice đơn giản như sau:

bảng Notice

bảng Notice

Mực đích của bảng này của tôi là lưu lại các thông báo của người dùng trong trường hợp người dùng không online trên hệ thống thì khi họ online họ có thể biết được có những thông báo nào đã được gửi đến cho mình.

Rồi giờ chúng ta hãy xử lý các logic gửi thông báo tại file NoticeController. Tại file NoticeController tôi sẽ tạo một hàm addNotice như sau.

hàm xử lý notice

hàm xử lý notice

Nhiệm vụ của hàm này khá là đơn giản lưu thông tin thông báo vào database và kích hoạt sự kiên NoticeEvent để gửi thông báo đến các client đang kết nối vào boardcast thông qua hàm event như trên.

Đây là đoạn code kích hoạt sự kiện gửi message thông qua pusher.

code gửi message

code gửi message

Như vậy là xong chúng ta đã xử lý xong phần gửi message từ sever đi rồi. Tiếp theo chúng ta sẽ làm phần xử lý phía client.

Đầu tiên chúng cần tạo một component Notification cơ bản như sau.

component notification

component notification

Code:

return (

        <>

            <section className="logo">

                <i

                    style={{

                        fontSize: "34pt",

                        color: "white"

                    }}

                    className="fas fa-bell"

                ></i>

                <span

                    onClick={handledShow}

                    ref={refCount}

                    style={{

                        position: "absolute",

                        top: "10px",

                        right: "30px",

                        cursor: "pointer"

                    }}

                    className="count"

                >

                    0

                </span>

                <ul

                    style={show ? { display: "block" } : { display: "none" }}

                    className="listnotication"

                >

                    {listNotice}

                    {data.length > 0 ? (

                        <li onClick={handelMark} className="mark">

                            Đánh dấu tất cả đã đọc

                        </li>

                    ) : (

                        ""

                    )}

                </ul>

            </section>

        </>

    );
Cách tạo khá là đơn giản phải không nào.
Giờ chúng ta hãy chạy lệnh sau để cài thư viện pusher laravel echo vào dự án react của mình
npm install --save laravel-echo pusher-js
Sau khi cài xong ở component Notication chúng ta sẽ import thư viện laravel echo vào như sau:
import Echo from "laravel-echo";
Sau đó chúng ta sẽ cài đặt các cấu hình cho thư viện theo các thông tin mà trang pusher đã cung cấp cho bạn như thông tin cấu hình của tôi là như sau.
 window.Pusher = require("pusher-js");

    window.Echo = new Echo({

        broadcaster: "pusher",

        key: "a91bfcfd34b8817c5109",

        cluster: "ap1",

        forceTLS: true

    });
Sau khi đã cấu hình xong bạn hãy tạo một Effect để kết nối đến channel của bạn khi ứng dụng được khởi tạo như sau.
  useEffect(() => {

        var channel = window.Echo.channel("my-channel");

        channel.listen(".my-event", function(res) {

            setData([...data, res.message]);

        });

    }, []);
Như vậy là xong bạn đã kết nối đến boardcast Pusher của mình rồi giờ khi nào có message từ server được gửi đi thì client sẽ nhận được và sẽ thêm dữ liệu đã nhận được vào state data để hiển thị thông báo cho bạn.
Sau đây là toàn bộ code của component Notication
import React, { useEffect, useMemo, useRef, useState } from "react";

import { useDispatch, useSelector } from "react-redux";

import "../sass/notication.scss";

import { GETNOTICATION, READNOTICATION } from "../action/mainAction";

import { uniqueId } from "lodash";

import Echo from "laravel-echo";

import moment from "moment";

function Notication(props) {

    // Cáu hình thư viện pusher

    window.Pusher = require("pusher-js");

    window.Echo = new Echo({

        broadcaster: "pusher",

        key: "a91bfcfd34b8817c5109",

        cluster: "ap1",

        forceTLS: true

    });

    useEffect(() => {

        // lấy danh sách các thông báo từ server khi mà người dùng không online

        getNotification();

    }, []);

    useEffect(() => {

        // Kết nối đến Boardcast

        var channel = window.Echo.channel("my-channel");

        channel.listen(".my-event", function(res) {

            setData([...data, res.message]);

        });

    }, []);

    // State trạng thái hiển thị danh sách thông báo

    const [show, setShow] = useState(false);

    // State lưu trữ danh sách các thông báo

    const [data, setData] = useState([]);

    const dispatch = useDispatch();

    // Ref của thành phần hiển thị số thông báo chưa đọc

    const refCount = useRef();

    // Hàm lấy danh sách thông báo từ server sử dụng redux saga

    function getNotification() {

        dispatch({ type: GETNOTICATION, payload: setData });

    }

    // Hàm hiển thị danh sách các thông báo

    function handledShow() {

        if (show == false) {

            setShow(true);

        } else {

            setShow(false);

        }

    }

    // Hàm đánh dấu tất cả thông báo đều đã đọc

    function handelMark() {

        dispatch({ type: READNOTICATION });

        refCount.current.textContent = 0;

    }

    const listNotice = useMemo(() => showNotication(), [data]);

    // Hàm hiển thị danh sách thông báo

    function showNotication() {

        if (data.length > 0) {

            let number = 0;

            return data.map(item => {

                if (item.userId == localStorage.userId) {

                    number++;

                    refCount.current.textContent = number;

                    return (

                        <li

                            key={uniqueId("notification")}

                            className="itemNotication"

                        >

                            <section className="content-notication">

                                <p className="time">

                                    {moment(item.time).format("DD/MM/YYYY")}

                                </p>

                                <p style={{ marginBottom: 0 }}>{item.msg}</p>

                            </section>

                        </li>

                    );

                }

            });

        } else {

            return (

                <li className="itemNotication">

                    <section className="content-notication">

                        <p className="time"></p>

                        <p style={{ marginBottom: 0 }}>

                            Không có thông báo mới

                        </p>

                    </section>

                </li>

            );

        }

    }

    return (

        <>

            <section className="logo">

                <i

                    style={{

                        fontSize: "34pt",

                        color: "white"

                    }}

                    className="fas fa-bell"

                ></i>

                <span

                    onClick={handledShow}

                    ref={refCount}

                    style={{

                        position: "absolute",

                        top: "10px",

                        right: "30px",

                        cursor: "pointer"

                    }}

                    className="count"

                >

                    0

                </span>

                <ul

                    style={show ? { display: "block" } : { display: "none" }}

                    className="listnotication"

                >

                    {listNotice}

                    {data.length > 0 ? (

                        <li onClick={handelMark} className="mark">

                            Đánh dấu tất cả đã đọc

                        </li>

                    ) : (

                        ""

                    )}

                </ul>

            </section>

        </>

    );

}

export default Notication;
Như vậy là tôi đã hướng dẫn các bạn làm chức năng thông báo bằng laravel và reactjs một cách đơn giản nhất rồi, cảm ơn các bạn đã theo dõi và hẹn gặp lại các bạn ở các bài viết sau.