Skip to content

Instantly share code, notes, and snippets.

@paoloricciuti
Last active October 3, 2022 14:56
Show Gist options
  • Select an option

  • Save paoloricciuti/cc54657f4c4a113be9327186162775cd to your computer and use it in GitHub Desktop.

Select an option

Save paoloricciuti/cc54657f4c4a113be9327186162775cd to your computer and use it in GitHub Desktop.
useBroadcast.ts
import {
Dispatch,
SetStateAction,
useCallback,
useEffect,
useRef,
useState,
} from 'react';
/**
* Hook to create a state variable that it's keep in sync with other tabs
* of the same domain opened in the same browser.
* @param {string} name The name of the broadcast to sync with other tabs
* @param {any | ()=>any} initialState The initial state of the hook
* @returns {Array} An array with [state, setState]
*/
export default function useBroadcast<T>(
name: string,
initialState: T | (() => T) = undefined
): readonly [T, Dispatch<SetStateAction<T>>] {
const [value, _setValue] = useState(initialState);
const broadcastChannelRef = useRef<BroadcastChannel>();
useEffect(() => {
//create a new BroadcastChannel with the passed in name
broadcastChannelRef.current = new BroadcastChannel(name);
//when the callback is called set the value with the new data
const cb = ({ data }) => {
_setValue(data);
};
//add a message event listener on the broadcast
broadcastChannelRef.current.addEventListener('message', cb);
return () => {
//clean up the event listener
broadcastChannelRef.current.removeEventListener('message', cb);
broadcastChannelRef.current.close();
};
}, [name]);
const setValue: Dispatch<SetStateAction<T>> = useCallback(
(newValue) => {
//get the new value
let toSet = newValue;
if (typeof newValue === 'function') {
toSet = (newValue as Function)(value);
}
//set the value and post a message on the broadcast channel
_setValue(toSet);
if (broadcastChannelRef.current) {
broadcastChannelRef.current.postMessage(toSet);
}
},
[value]
);
return [value, setValue] as const;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment