Skip to content

Commit fbd7d26

Browse files
Merge pull request #443 from laravel/broadcast-events
Added useEchoNotification hook
2 parents 14b3717 + 6f56305 commit fbd7d26

File tree

8 files changed

+805
-0
lines changed

8 files changed

+805
-0
lines changed

packages/react/src/hooks/use-echo.ts

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { type BroadcastDriver } from "laravel-echo";
22
import { useCallback, useEffect, useRef } from "react";
33
import { echo } from "../config";
44
import type {
5+
BroadcastNotification,
56
Channel,
67
ChannelData,
78
ChannelReturnType,
@@ -163,6 +164,91 @@ export const useEcho = <
163164
};
164165
};
165166

167+
export const useEchoNotification = <
168+
TPayload,
169+
TDriver extends BroadcastDriver = BroadcastDriver,
170+
>(
171+
channelName: string,
172+
callback: (payload: BroadcastNotification<TPayload>) => void = () => {},
173+
event: string | string[] = [],
174+
dependencies: any[] = [],
175+
) => {
176+
const result = useEcho<BroadcastNotification<TPayload>, TDriver, "private">(
177+
channelName,
178+
[],
179+
callback,
180+
dependencies,
181+
"private",
182+
);
183+
184+
const events = useRef(
185+
toArray(event)
186+
.map((e) => {
187+
if (e.includes(".")) {
188+
return [e, e.replace(/\./g, "\\")];
189+
}
190+
191+
return [e, e.replace(/\\/g, ".")];
192+
})
193+
.flat(),
194+
);
195+
const listening = useRef(false);
196+
const initialized = useRef(false);
197+
198+
const cb = useCallback(
199+
(notification: BroadcastNotification<TPayload>) => {
200+
if (!listening.current) {
201+
return;
202+
}
203+
204+
if (
205+
events.current.length === 0 ||
206+
events.current.includes(notification.type)
207+
) {
208+
callback(notification);
209+
}
210+
},
211+
dependencies.concat(events.current).concat([callback]),
212+
);
213+
214+
const listen = useCallback(() => {
215+
if (listening.current) {
216+
return;
217+
}
218+
219+
if (!initialized.current) {
220+
result.channel().notification(cb);
221+
}
222+
223+
listening.current = true;
224+
initialized.current = true;
225+
}, [cb]);
226+
227+
const stopListening = useCallback(() => {
228+
if (!listening.current) {
229+
return;
230+
}
231+
232+
listening.current = false;
233+
}, [cb]);
234+
235+
useEffect(() => {
236+
listen();
237+
}, dependencies.concat(events.current));
238+
239+
return {
240+
...result,
241+
/**
242+
* Stop listening for notification events
243+
*/
244+
stopListening,
245+
/**
246+
* Listen for notification events
247+
*/
248+
listen,
249+
};
250+
};
251+
166252
export const useEchoPresence = <
167253
TPayload,
168254
TDriver extends BroadcastDriver = BroadcastDriver,

packages/react/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ export { configureEcho, echo } from "./config/index";
22
export {
33
useEcho,
44
useEchoModel,
5+
useEchoNotification,
56
useEchoPresence,
67
useEchoPublic,
78
} from "./hooks/use-echo";

packages/react/src/types.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@ export type Channel = {
1616
visibility: "private" | "public" | "presence";
1717
};
1818

19+
export type BroadcastNotification<TPayload> = TPayload & {
20+
id: string;
21+
type: string;
22+
};
23+
1924
export type ChannelReturnType<
2025
T extends BroadcastDriver,
2126
V extends Channel["visibility"],

0 commit comments

Comments
 (0)