skip to content

With React Native's NetInfo, what is the difference between isConnected and isInternetReachable, and which should drive an offline banner?

level: middleimportance: must knowfreq 55%

answer

  1. a link is not the internet
  2. hotel Wi-Fi login page
  3. null means not yet known
  4. Android validation vs an HTTP probe
  5. banner only on an explicit false

basics

~20 s

isConnected says the device has an active network link; isInternetReachable says that link actually reaches the internet, and is null while unknown. Drive an offline banner from isInternetReachable === false, never from null, and still treat failed API calls as the final word.

solid answer

~50 s

`isConnected` is true when the phone has an active network such as Wi-Fi or cellular. That says nothing about the internet: a captive-portal hotel Wi-Fi or a router with a dead uplink is connected but useless. `isInternetReachable` answers the second question. On Android, NetInfo takes it from the OS, which marks a network validated once it has confirmed internet access; on iOS, the library itself sends a `HEAD` request to `reachabilityUrl` and expects a `204`. Until that answer exists the value is `null`, which means unknown, not offline. So for the field-inspection app's banner I show "Offline" only when `isInternetReachable === false`, show nothing (or a neutral state) for `null`, and debounce flapping. Reachability is still a hint: a failed request to our own API is the real signal, and screens should handle it regardless of the banner.

code

tsx · 21 lines
tsx
import { useEffect, useState } from 'react';
import { Text, View } from 'react-native';
import { useNetInfo } from '@react-native-community/netinfo';

export function OfflineBanner() {
  const { isInternetReachable } = useNetInfo();
  const offlineNow = isInternetReachable === false; // null means unknown
  const [visible, setVisible] = useState(false);

  useEffect(() => {
    const t = setTimeout(() => setVisible(offlineNow), 1500);
    return () => clearTimeout(t);
  }, [offlineNow]);

  if (!visible) return null;
  return (
    <View accessibilityRole="alert" style={{ padding: 8 }}>
      <Text>Offline: inspections will sync when you are back online.</Text>
    </View>
  );
}

go deeper

for a junior

Recall that isConnected means a network link and isInternetReachable means real internet access, and that null means unknown.

for a middle

Explain the captive-portal case, how Android validation and the iOS HEAD probe produce the value, and why a banner should test === false.

for a senior

Build a banner that debounces flapping, never blocks the user, and treats failed API calls as the authoritative signal over reachability.

for a principal

Define the app's offline contract: what users can do offline, what the banner promises, and how reachability, API errors and sync status combine into one honest state.

## Two different questions `@react-native-community/netinfo` reports a `NetInfoState` object. Two of its fields are easy to confuse: - **`isConnected`** – is there an **active network link**? True on Wi-Fi or cellular, false when the type is `none`. - **`isInternetReachable`** – can that link **reach the internet**? `true`, `false`, or `null` when it has not been determined yet. The gap between them is where real users live: | Situation | `isConnected` | `isInternetReachable` | |---|---|---| | Airplane mode | `false` | `false` | | Normal Wi-Fi or 5G | `true` | `true` | | Hotel Wi-Fi waiting for a login page | `true` | `false` | | Router with a dead uplink | `true` | `false` | | App just launched, check still running | `true` | `null` | ## How each platform decides reachability NetInfo 12 fills `isInternetReachable` differently per platform: - **Android** – the native module reports it directly: the active network must have the internet capability and be **validated** by the OS (and not suspended). Because the default `useNativeReachability: true` accepts a native boolean, no extra HTTP request is made. - **iOS** – the native module reports only the link. NetInfo then runs its **own HTTP probe**: a `HEAD` request to `reachabilityUrl` (by default a Google `generate_204` endpoint), expecting status `204`. It re-checks every 60 seconds while reachable and every 5 seconds while not, with a 15-second request timeout. While a check is pending, the value is `null`. A hook-based component also starts with `type: 'unknown'`, `isConnected: null` and `isInternetReachable: null` before the first event arrives. ## Designing the offline banner In the field-inspection app, inspectors walk through basements and rural sites; the banner tells them their reports will sync later. The rules that make it trustworthy: 1. **Show "Offline" only on an explicit `false`.** Test `isInternetReachable === false`, not `!isInternetReachable`, because `null` would otherwise flash an offline banner on every launch. 2. **Treat `null` as unknown.** Render nothing, or a neutral "checking" state if the screen needs one. 3. **Debounce transitions.** Signal flaps in and out in lifts and tunnels; wait a second or two before showing or hiding the banner so it does not flicker. 4. **Do not block the UI on it.** Let inspectors keep working; the banner informs, it does not gate. 5. **Trust your API over the banner.** Even `true` only means a generic endpoint answered. Your backend can be down, blocked or slow, so every request still needs its own error handling. Common mistakes to avoid: - Using `isConnected` alone, which reports "online" behind a captive portal. - Checking `!state.isInternetReachable`, which treats unknown as offline. - Disabling submit buttons whenever reachability is not `true`, which strands users on a slow first check. - Assuming the iOS and Android values are computed the same way; they are not. ## Testing the banner Reachability bugs rarely show up on a developer's office Wi-Fi, so reproduce the states deliberately: - **Airplane mode** gives `isConnected: false`; the banner should appear after the debounce. - **A Wi-Fi network with no uplink**, such as a travel router with its WAN cable unplugged, produces the connected-but-unreachable case. - **A captive portal**, or a firewall rule that blocks the probe host, shows whether the banner reacts to `false` rather than to the link. - **Cold start** confirms nothing flashes while the value is still `null`. - **Both platforms**, because Android relies on the OS's validation and iOS on NetInfo's HTTP probe, so timing differs: Android can flip quickly on a network change, while iOS may take up to one probe cycle. In unit tests, NetInfo ships a Jest mock; drive the hook's state from the test rather than from a real network. ## What about expo-network? Expo's `expo-network` exposes a similarly named field, but on iOS its `isInternetReachable` always equals `isConnected`, so it cannot detect the captive-portal case there. If that distinction matters on iOS, NetInfo's probe is the tool. ## The interview answer Define both fields in one sentence each, give the captive-portal example, explain the `null` state, and name the rule: **banner on `=== false`, debounce, and let failed API calls decide**. Mentioning that Android uses OS validation while iOS relies on NetInfo's HTTP probe shows you know where the value comes from.

  • Why does isInternetReachable start as null right after launch?
    The hook's initial state is unknown until the first NetInfo event arrives, and on iOS the library must finish its HTTP probe to `reachabilityUrl` before it can say true or false. Treat `null` as not yet known and render no offline banner for it.
  • The banner says online, but uploads fail. How can both be true?
    Reachability only proves that the device could reach one test endpoint, or that Android validated the network. Your API may be down, blocked on that network, or timing out. Handle request failures independently, and optionally point NetInfo's `reachabilityUrl` at your own health endpoint.
  • Would you disable the Submit button while offline?
    Usually not. The value can be wrong or stale in both directions, so blocking actions on it frustrates users. Let them submit, save locally, and show the banner as information; the sync layer decides when to send.

isConnected is the lift doors opening; isInternetReachable is whether the floor behind them is actually open for business. Null is the doors still sliding: you do not yet know, so you should not announce that the building is closed.

saying these in an interview costs you the question

  • isConnected true means the app can reach its backend.
  • A null isInternetReachable should be shown as offline.
  • Both platforms compute isInternetReachable with the same HTTP ping.
  • If NetInfo says reachable, API requests do not need error handling.
  • isInternetReachable is always a boolean once the app has started.