Overview
src/services/syncService.ts and src/services/pushNotifications.ts register Zustand store subscriptions in constructors or module-level initialization code. In React development mode (StrictMode), effects and constructors may run twice. If these services are initialized inside React components or useEffects without proper cleanup, a second subscription is registered without the first being removed, causing event handlers to fire twice for every state change (double sync, double notification handling).
Specifications
Features:
- Each service maintains a single active store subscription at any time
initialize() checks for existing subscription before registering new one
destroy() unsubscribes all listeners
- StrictMode double-invoke does not result in duplicate listeners
Tasks:
- In
SyncService and PushNotificationService, store subscription return values
- Add guard:
if (this.subscription) return; this.subscription = store.subscribe(...)
- Implement
destroy() calling this.subscription?.(); this.subscription = null;
- Ensure services initialized in
useEffect return cleanup calling destroy()
- Add unit test confirming single subscription after double
initialize() call
Impacted Files:
src/services/syncService.ts
src/services/pushNotifications.ts
App.tsx or service initialization
Acceptance Criteria
- Double `initialize()" call results in exactly 1 active subscription
- Store state change triggers event handler exactly once
destroy() removes subscription cleanly
- Unit test confirms event handler called once (not twice) after double init
Overview
src/services/syncService.tsandsrc/services/pushNotifications.tsregister Zustand store subscriptions in constructors or module-level initialization code. In React development mode (StrictMode), effects and constructors may run twice. If these services are initialized inside React components oruseEffects without proper cleanup, a second subscription is registered without the first being removed, causing event handlers to fire twice for every state change (double sync, double notification handling).Specifications
Features:
initialize()checks for existing subscription before registering new onedestroy()unsubscribes all listenersTasks:
SyncServiceandPushNotificationService, store subscription return valuesif (this.subscription) return; this.subscription = store.subscribe(...)destroy()callingthis.subscription?.(); this.subscription = null;useEffectreturn cleanup callingdestroy()initialize()callImpacted Files:
src/services/syncService.tssrc/services/pushNotifications.tsApp.tsxor service initializationAcceptance Criteria
destroy()removes subscription cleanly