TanStack / TanStack/db

ReactNativeOnlineDetector sometimes never fires after offline -> online transition

Open
#1,490 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
3.9k
Forks
266
Avg merge
1d 4h
Merged PRs (30d)
55

Description

  • I've validated the bug against the latest version of DB packages

Describe the bug
ReactNativeOnlineDetector sometimes never calls notifyListeners on the offline->online transition. When this happens, the offline executor stops retrying pending transactions until the app is foregrounded (which triggers notifyListeners via the AppState path). The app otherwise appears healthy, the outbox has the transaction, the network is back, but no sync attempt is ever made.

To Reproduce

  1. Run a React Native app (Expo dev client) that uses startOfflineExecutor from @tanstack/offline-transactions/react-native. Reach a real remote server (I tested over Tailscale).
  2. With the app in the foreground and online, enable airplane mode.
  3. Create a pending transaction via createOfflineAction(...). Confirm the outbox contains 1 item (e.g. via executor.getPendingCount()).
  4. Disable airplane mode. Network is back within a few seconds.
  5. Wait. The executor never retries, no [Sync] logs, no fetch attempts, pending count stays at 1 indefinitely.
  6. Background the app and foreground it again. Sync runs immediately.

Expected behavior
After the device returns online, the executor should retry the pending transaction within a short window — the same way foregrounding the app currently causes it to retry.

Smartphone:

  • Device: Google Pixel 9
  • OS: GrapheneOS
  • App runtime: Expo SDK 55, React Native 0.83.4, @react-native-community/netinfo 11.5.2
  • @tanstack/offline-transactions: 1.0.30 , @tanstack/db: 0.6.5

Additional context
Looking at packages/offline-transactions/src/connectivity/ReactNativeOnlineDetector.ts, two things seem worth looking at together:

  1. Edge detection via !this.wasConnected: if the cache drifts out of sync with reality, the edge check silently fails forever.
  2. startListening() has an async NetInfo.fetch().then(state => this.wasConnected = ...) running alongside the synchronous addEventListener handler, which also writes wasConnected. If fetch() resolves after one or more events have already fired, it can overwrite a correct wasConnected with a stale one.

Empirically on our device, after airplane-mode toggling, wasConnected ends up stuck at true, so the subsequent online event evaluates as true && !true → no notifyListeners. AppState → active fires notifyListeners directly without consulting wasConnected, which is why backgrounding+foregrounding recovers.

For comparison, WebOnlineDetector in the same package has no edge detection and no cached state. It calls notifyListeners() on every window.online event and answers isOnline() by reading navigator.onLine live.

Workaround

Passing a custom OnlineDetector to startOfflineExecutor that notifies on every online NetInfo event (mirroring the web detector's behavior) eliminates the issue.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with packages/offline-transactions/src/connectivity/ReactNativeOnlineDetector.ts, tracing startListening(), NetInfo.fetch(), the event handler, and the wasConnected cache. Reproduce the airplane-mode transition described in the issue and compare it with WebOnlineDetector; done means an online transition reliably calls notifyListeners so the pending executor retries without foregrounding the app.

Written by the indexing model from the issue text.

Assessment

Tech stack
react-native, typescript
Domain
mobile-dev
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
68/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.