docs(react-native): fix example to include initial state#10172
docs(react-native): fix example to include initial state#10172roitium wants to merge 1 commit intoTanStack:mainfrom
Conversation
|
📝 WalkthroughWalkthroughUpdates React Native documentation to show initial asynchronous network state fetching using Expo Network API before event listener setup. Initializes online state from network state before subscribing to state change events. Only additions, no deletions or signature changes. Changes
Poem
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes 🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@docs/framework/react/react-native.md`:
- Around line 43-53: The async init in onlineManager.setEventListener can be
overwritten by a later listener event and lacks error handling: introduce a
local guard flag (e.g., "initialResultIgnored" or "stale") inside the
setEventListener callback that is flipped when the synchronous
addNetworkStateListener fires (or when its callback runs) so the Promise result
from Network.getNetworkStateAsync() only calls setOnline if the listener hasn't
already provided a newer state; also attach .catch(...) to
getNetworkStateAsync() to log/handle errors, and ensure you still return
eventSubscription.remove from the setEventListener callback (use the same
identifiers: Network.getNetworkStateAsync, Network.addNetworkStateListener,
setOnline, eventSubscription.remove).
| onlineManager.setEventListener((setOnline) => { | ||
| Network.getNetworkStateAsync().then((state) => { | ||
| setOnline(!!state.isConnected) | ||
| }) | ||
|
|
||
| const eventSubscription = Network.addNetworkStateListener((state) => { | ||
| setOnline(!!state.isConnected) | ||
| }) | ||
|
|
||
| return eventSubscription.remove | ||
| }) |
There was a problem hiding this comment.
Race condition: async fetch result can overwrite a more recent listener-fired state
Because getNetworkStateAsync() is asynchronous, the following sequence is possible:
getNetworkStateAsync()is invoked — captures state at T₀ (e.g., offline).addNetworkStateListeneris registered synchronously.- A state change fires the listener at T₁ →
setOnline(true). - The async call resolves at T₂ with the stale T₀ snapshot →
setOnline(false), silently overwriting the correct current state.
A guard flag prevents the async snapshot from clobbering a fresher listener result:
🐛 Proposed fix with race-safe initialization guard + error handling
onlineManager.setEventListener((setOnline) => {
- Network.getNetworkStateAsync().then((state) => {
- setOnline(!!state.isConnected)
- })
-
- const eventSubscription = Network.addNetworkStateListener((state) => {
+ let initialised = false
+
+ const eventSubscription = Network.addNetworkStateListener((state) => {
+ initialised = true
setOnline(!!state.isConnected)
})
-
+
+ Network.getNetworkStateAsync()
+ .then((state) => {
+ if (!initialised) {
+ setOnline(!!state.isConnected)
+ }
+ })
+ .catch(() => {
+ // getNetworkStateAsync can reject on some platforms/SDK versions
+ })
+
return eventSubscription.remove
})Additionally, the bare .then() with no .catch() means that if getNetworkStateAsync() rejects (e.g., the native module is unavailable, which surfaces as an unhandled promise rejection), the error is silently swallowed and will appear as an unhandled rejection in the app. The .catch() in the proposed fix addresses both concerns.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| onlineManager.setEventListener((setOnline) => { | |
| Network.getNetworkStateAsync().then((state) => { | |
| setOnline(!!state.isConnected) | |
| }) | |
| const eventSubscription = Network.addNetworkStateListener((state) => { | |
| setOnline(!!state.isConnected) | |
| }) | |
| return eventSubscription.remove | |
| }) | |
| onlineManager.setEventListener((setOnline) => { | |
| let initialised = false | |
| const eventSubscription = Network.addNetworkStateListener((state) => { | |
| initialised = true | |
| setOnline(!!state.isConnected) | |
| }) | |
| Network.getNetworkStateAsync() | |
| .then((state) => { | |
| if (!initialised) { | |
| setOnline(!!state.isConnected) | |
| } | |
| }) | |
| .catch(() => { | |
| // getNetworkStateAsync can reject on some platforms/SDK versions | |
| }) | |
| return eventSubscription.remove | |
| }) |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@docs/framework/react/react-native.md` around lines 43 - 53, The async init in
onlineManager.setEventListener can be overwritten by a later listener event and
lacks error handling: introduce a local guard flag (e.g., "initialResultIgnored"
or "stale") inside the setEventListener callback that is flipped when the
synchronous addNetworkStateListener fires (or when its callback runs) so the
Promise result from Network.getNetworkStateAsync() only calls setOnline if the
listener hasn't already provided a newer state; also attach .catch(...) to
getNetworkStateAsync() to log/handle errors, and ensure you still return
eventSubscription.remove from the setEventListener callback (use the same
identifiers: Network.getNetworkStateAsync, Network.addNetworkStateListener,
setOnline, eventSubscription.remove).
🎯 Changes
expo-networkdoes not emit the current state immediately upon subscription. This causes onlineManager to default to "online" on cold starts, even if the device is actually offline. So we need to explicitly callNetwork.getNetworkStateAsync()to initialize the state correctly before setting up the listener.✅ Checklist
pnpm run test:pr.🚀 Release Impact
Summary by CodeRabbit