Update 2024 use tab-election.
We had some problems with multiple tabs that are pretty common:
- Writing to storage could collide or not get picked up
- Logout in one tab would not be noticed in the other
- Sync with the backend would be done independently by all
Being Uclusion we of course used a Uclusion Dialog to decide and the options were:
- broadcast-channel the NPM package
- Broadcast channel API
- Service worker communication
Pretty easy decision because in addition to using broadcast channel API when available the NPM package supported leader selection. That allowed us to set up a React context to let us know anywhere in the code whether our tab was leader or not - see code here.
We could also send messages to the other tabs telling them to refresh from IndexedDB like so
const myChannel = new BroadcastChannel(COMMENTS_CHANNEL); return myChannel.postMessage('comments').then(() => myChannel.close()) .then(() => console.info('Update comment context sent.'));
Now the basic idea we followed was the leader syncs from the backend and stores in an IndexedDB namespace and all other tabs store their local edits in a differently named IndexedDB namespace. Its very unlikely more than one tab is doing local edits at a time and even if somehow they were the sync from the network is the eventual master.
Also very simple logout broadcasts a message which is listened for by the other tabs here
const [logoutChannel, setLogoutChannel] = useState(undefined); useEffect(() => { console.info('Setting up logout channel'); const myLogoutChannel = new BroadcastChannel('logout'); myLogoutChannel.onmessage = () => { console.info('Logging out from message'); onSignOut().then(() => console.info('Done logging out')); } setLogoutChannel(myLogoutChannel); return () => {}; }, []);
Top comments (0)