rooks
Version:
Collection of awesome react hooks
86 lines (84 loc) • 2.28 kB
JavaScript
// src/hooks/useBroadcastChannel.ts
import { useCallback, useEffect, useMemo, useRef } from "react";
function isEventLike(error) {
return error instanceof Event || error instanceof Error;
}
function useBroadcastChannel(channelName, options) {
const { onMessage, onError } = options || {};
const isSupported = useMemo(() => {
return typeof window !== "undefined" && typeof BroadcastChannel !== "undefined";
}, []);
const channelRef = useRef(null);
const stableOnMessage = useCallback(
(event) => {
if (onMessage) {
onMessage(event.data);
}
},
[onMessage]
);
const stableOnError = useCallback(
(event) => {
if (onError) {
onError(event);
}
},
[onError]
);
useEffect(() => {
if (!isSupported) {
return;
}
try {
const channel = new BroadcastChannel(channelName);
channelRef.current = channel;
channel.addEventListener("message", stableOnMessage);
channel.addEventListener("messageerror", stableOnError);
return () => {
channel.removeEventListener("message", stableOnMessage);
channel.removeEventListener("messageerror", stableOnError);
channel.close();
channelRef.current = null;
};
} catch (error) {
if (onError && isEventLike(error)) {
onError(error);
}
}
}, [channelName, isSupported, stableOnMessage, stableOnError, onError]);
const postMessage = useCallback(
(data) => {
if (!isSupported) {
console.warn("useBroadcastChannel: BroadcastChannel API is not supported");
return;
}
if (!channelRef.current) {
console.warn("useBroadcastChannel: Channel is not initialized");
return;
}
try {
channelRef.current.postMessage(data);
} catch (error) {
console.error("useBroadcastChannel: Failed to post message", error);
if (onError && isEventLike(error)) {
onError(error);
}
}
},
[isSupported, onError]
);
const close = useCallback(() => {
if (channelRef.current) {
channelRef.current.close();
channelRef.current = null;
}
}, []);
return {
postMessage,
close,
isSupported
};
}
export {
useBroadcastChannel
};