Skip to content

Instantly share code, notes, and snippets.

@sudkumar
Last active April 12, 2024 07:50
Show Gist options
  • Star 11 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save sudkumar/c84be58dd644730fd3ce0ebae98a56db to your computer and use it in GitHub Desktop.
Save sudkumar/c84be58dd644730fd3ce0ebae98a56db to your computer and use it in GitHub Desktop.
Web-Sockets in ReactJS with PusherJs and Laravel Echo with public and private channels
import React, { useEffect, useState, useMemo } from "react"
import Echo from "laravel-echo"
import Pusher from "pusher-js"
/**
* Pusher configuration
*/
const pusherConfig = {
key: '<your_pusher_key_here>',
cluster: '<pusher_cluster>',
// auth endpoint for private channels
// e.g. for Laravel https://example.com/api/broadcasting/auth
authEndpoint: '<auth_endpoint_for_private_channels>'
}
/**
* Context for Channels
*/
type TChannels = Echo | undefined
const ChannelsContext = React.createContext<TChannels>(undefined)
/**
* Channel Context Provider
*/
export function ChannelsProvider({
children,
authUser,
authToken
}: {
children: React.ReactNode,
authUser?: any
authToken?: string
}) {
const [channels, setChannels] = useState<TChannels>(undefined)
useEffect(() => {
const channels = getChannels(pusherConfig, authToken);
setChannels(channels)
return () => {
// disconnect from server and reset the channels
channels.disconnect()
setChannels(undefined)
}
}, [authUser, authToken])
return (
<ChannelContext.Provider value={channels}>
{children}
</ChannelContext.Provider>
)
}
/**
* Hook to use the channels provided via context
*/
export function useChannels() {
const channels = React.useContext(ChannelsContext)
return channels
}
/**
* Use private channels
* It simple return the useChannels with authenticated user bindings
*/
export function usePrivateChannels (authUserId: any) {
const channels = useChannels()
return useMemo(() => {
return channels && channels.private("users." + authUserId)
}, [channels, authUserId])
}
/**
* Get the channels
*/
function getChannels(pusherConfig: typeof pusherConfig, authToken?: string) {
const client = new Pusher(pusherConfig.key, {
cluster: pusherConfig.cluster,
forceTLS: true,
authEndpoint: pusherConfig.authEndpoint,
auth: authToken ? {
headers: {
// pass the authorization token when using private channels
Authorization: `Bearer ${authToken}`,
},
}: undefined,
})
const channels = new Echo({
broadcaster: "pusher",
client: client,
})
return channels
}
import React, { useEffect } from 'react'
import { ChannelsProvider, usePrivateChannels } from "./channels"
// FIRST: we will wrap our application with the `ChannelsProvider`
function App () {
// get the user and the access token SOMEHOW!
const user = getUser() // via context or any other way
const token = getToken() // via local storage or any other ways
return <ChannelsProvider authUser={user} authToken={token}>
<Notifications authUserId={user.id} />
</ChannelsProvider>
}
// Next, we will listen to a private channel for an event
// and update the data on events
// A channel listens to a particular event
// Here is an example event from Laravel when sending notifications
const NOTIFICATION_EVENT =
".Illuminate\\Notifications\\Events\\BroadcastNotificationCreated"
interface INotification {
id: number,
content: string
}
/**
* Our notification channel which notif
*/
function useNotificationChannel (
authUserId: integer,
onChange: (notification: INotification) => void
) {
const channels = usePrivateChannels(authUserId)
useEffect(() => {
if (channels) {
channels.listen(NOTIFICATION_EVENT, onChange)
// same as channels.notification(onChange)
return () => {
channels.stopListening(NOTIFICATION_EVENT)
}
}
}, [channels, onChange])
}
export function Notifications({ authUserId }: { authUserId: integer }) {
const [notifications, setNotifications] = useState<Array<INotification>>([])
const handleNotificationsEvent = useCallback((notification: INotification) => {
setNotifications(
existingNotifications => ([notification].concat(existingNotifications))
)
})
useNotificationChannel(authUserId, handleNotificationsEvent)
return <ol>
{notifications.map(n => <li key={n.id}>{n.content}</li>}
</ol>
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment