Created
March 12, 2026 22:38
-
-
Save panayotoff/f2fca72a76b2d80ab74405ebe1863fc6 to your computer and use it in GitHub Desktop.
useBroadcastChannel React/Typescript hook
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import { useCallback, useEffect, useRef, useState } from "react"; | |
| type UseBroadcastChannelOptions<T> = { | |
| onMessage?: (message: T) => void; | |
| onError?: (error: Error | Event) => void; | |
| echo?: boolean; // whether sent messages should also be added locally | |
| }; | |
| const isSupported = | |
| typeof window !== "undefined" && "BroadcastChannel" in window; | |
| const useBroadcastChannel = <T = string>( | |
| topic: string, | |
| options: UseBroadcastChannelOptions<T> = {} | |
| ) => { | |
| const { onMessage, onError, echo = false } = options; | |
| const [messages, setMessages] = useState<T[]>([]); | |
| const channelRef = useRef<BroadcastChannel | null>(null); | |
| useEffect(() => { | |
| if (!isSupported) { | |
| onError?.(new Error("BroadcastChannel is not supported in this environment.")); | |
| return; | |
| } | |
| let channel: BroadcastChannel; | |
| try { | |
| channel = new BroadcastChannel(topic); | |
| channelRef.current = channel; | |
| } catch (error) { | |
| onError?.(error instanceof Error ? error : new Error("Failed to create BroadcastChannel.")); | |
| return; | |
| } | |
| const handleMessage = (event: MessageEvent<T>) => { | |
| setMessages(prev => [...prev, event.data]); | |
| onMessage?.(event.data); | |
| }; | |
| const handleMessageError = (event: MessageEvent) => { | |
| onError?.(event); | |
| }; | |
| channel.addEventListener("message", handleMessage); | |
| channel.addEventListener("messageerror", handleMessageError); | |
| return () => { | |
| channel.removeEventListener("message", handleMessage); | |
| channel.removeEventListener("messageerror", handleMessageError); | |
| channel.close(); | |
| if (channelRef.current === channel) { | |
| channelRef.current = null; | |
| } | |
| }; | |
| }, [topic, onMessage, onError]); | |
| const sendMessage = useCallback( | |
| (msg: T) => { | |
| const channel = channelRef.current; | |
| if (!channel) { | |
| onError?.(new Error("BroadcastChannel is not initialized.")); | |
| return false; | |
| } | |
| try { | |
| channel.postMessage(msg); | |
| if (echo) { | |
| setMessages(prev => [...prev, msg]); | |
| } | |
| return true; | |
| } catch (error) { | |
| onError?.(error instanceof Error ? error : new Error("Failed to post message.")); | |
| return false; | |
| } | |
| }, | |
| [echo, onError] | |
| ); | |
| const clearMessages = useCallback(() => { | |
| setMessages([]); | |
| }, []); | |
| return { | |
| messages, | |
| sendMessage, | |
| clearMessages, | |
| isSupported, | |
| }; | |
| }; | |
| export default useBroadcastChannel; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment