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)