
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.
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
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
interfaceShouldBroadcast
củ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àmbroadcastOn
và 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';
}
}

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
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
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
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>
</>
);
npm install --save laravel-echo pusher-js
import Echo from "laravel-echo";
window.Pusher = require("pusher-js");
window.Echo = new Echo({
broadcaster: "pusher",
key: "a91bfcfd34b8817c5109",
cluster: "ap1",
forceTLS: true
});
useEffect(() => {
var channel = window.Echo.channel("my-channel");
channel.listen(".my-event", function(res) {
setData([...data, res.message]);
});
}, []);
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;