This is a submission for DEV's Summer Bug Smash: Smash Stories powered by Sentry.
I was working on InnerHue, a mood-tracking app that stores mood entries in localStorage via a Zustand store. The reported bug: open the app in two tabs, log a mood in each, and entries would randomly go missing or get overwritten.
The investigation
The Zustand store (lib/useMoodStore.ts) kept an in-memory copy of moodHistory, but it never listened for changes coming from other tabs. So Tab A and Tab B each held their own stale snapshot, and whichever tab wrote to localStorage last simply clobbered whatever the other tab had written. Classic race condition, just spread across browser tabs instead of threads.
The fix
I added a window.addEventListener('storage', ...) listener that calls useMoodStore.persist.rehydrate() whenever the mood-storage key changes in another tab, keeping every open tab in sync instead of working off a frozen snapshot.
The bonus bug
While reproducing the race condition, I noticed something else: visiting a mood page kept creating duplicate entries. Turned out addMood() was called directly inside a useEffect with no guard, so React Strict Mode's dev-mode double-invocation of effects fired it twice. I added a useRef guard so it only fires once per genuine page visit.
Both bugs lived in the same localStorage write path, so I fixed them together in one PR.
PR: https://github.com/Nitya-003/InnerHue/pull/291
What I learned
Bugs that only reproduce with multiple tabs open are easy to miss in normal dev testing, so you have to deliberately go looking for them. It's a good reminder to test state-management code against concurrent access, not just sequential single-tab flows.
Top comments (1)
Multi-tab bugs are the worst because everything looks fine until you test the exact scenario you weren’t thinking about. ~