Skip to content

Instantly share code, notes, and snippets.

@sudkumar
Last active June 1, 2024 09:45
Show Gist options
  • 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>
}
@papaade
Copy link

papaade commented Jun 1, 2024

Please, do you it js version. and where would the configuration be in If it is used in nextjs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment