Introduction
Checking internet connectivity in React Native uses the @react-native-community/netinfo library, which provides a consistent API for network status monitoring across iOS and Android. It detects connection type (WiFi, cellular, none), whether the device is connected, and whether the connection can actually reach the internet. The library supports both event-based listeners for real-time monitoring and one-time checks with NetInfo.fetch().
Installation
1# Install the library
2npm install @react-native-community/netinfo
3# or
4yarn add @react-native-community/netinfo
5
6# iOS: install native pods
7cd ios && pod install && cd ..
For Expo managed projects, use expo install @react-native-community/netinfo which installs the compatible version automatically.
Basic Connection Check
1import NetInfo from '@react-native-community/netinfo';
2
3// One-time check
4const checkConnection = async () => {
5 const state = await NetInfo.fetch();
6 console.log('Connected:', state.isConnected);
7 console.log('Type:', state.type); // 'wifi', 'cellular', 'none'
8 console.log('Reachable:', state.isInternetReachable);
9
10 if (state.isConnected) {
11 console.log('Device is online');
12 } else {
13 console.log('Device is offline');
14 }
15};
state.isConnected checks if the device has a network interface active. state.isInternetReachable verifies the device can actually reach the internet (may be null initially while checking).
Real-Time Monitoring with Listener
1import React, { useEffect, useState } from 'react';
2import { View, Text, StyleSheet } from 'react-native';
3import NetInfo from '@react-native-community/netinfo';
4
5const App = () => {
6 const [isConnected, setIsConnected] = useState(true);
7 const [connectionType, setConnectionType] = useState('unknown');
8
9 useEffect(() => {
10 // Subscribe to network state changes
11 const unsubscribe = NetInfo.addEventListener(state => {
12 setIsConnected(state.isConnected);
13 setConnectionType(state.type);
14 });
15
16 // Cleanup on unmount
17 return () => unsubscribe();
18 }, []);
19
20 return (
21 <View style={styles.container}>
22 <Text style={styles.status}>
23 {isConnected ? 'Online' : 'Offline'}
24 </Text>
25 <Text>Connection type: {connectionType}</Text>
26 </View>
27 );
28};
29
30const styles = StyleSheet.create({
31 container: { flex: 1, justifyContent: 'center', alignItems: 'center' },
32 status: { fontSize: 24, fontWeight: 'bold' },
33});
NetInfo.addEventListener fires whenever the connection status changes. Always unsubscribe in the cleanup function to prevent memory leaks.
Custom Hook
1import { useEffect, useState } from 'react';
2import NetInfo from '@react-native-community/netinfo';
3
4export const useNetworkStatus = () => {
5 const [networkState, setNetworkState] = useState({
6 isConnected: true,
7 isInternetReachable: true,
8 type: 'unknown',
9 });
10
11 useEffect(() => {
12 const unsubscribe = NetInfo.addEventListener(state => {
13 setNetworkState({
14 isConnected: state.isConnected ?? false,
15 isInternetReachable: state.isInternetReachable ?? false,
16 type: state.type,
17 });
18 });
19 return () => unsubscribe();
20 }, []);
21
22 return networkState;
23};
24
25// Usage in any component
26const MyComponent = () => {
27 const { isConnected, isInternetReachable, type } = useNetworkStatus();
28
29 if (!isConnected) {
30 return <Text>No network connection</Text>;
31 }
32 if (!isInternetReachable) {
33 return <Text>Connected to {type} but no internet</Text>;
34 }
35 return <Text>Online via {type}</Text>;
36};
Offline Banner Component
1import React from 'react';
2import { View, Text, StyleSheet, Animated } from 'react-native';
3import { useNetworkStatus } from './useNetworkStatus';
4
5const OfflineBanner = () => {
6 const { isConnected } = useNetworkStatus();
7 const [slideAnim] = useState(new Animated.Value(-50));
8
9 useEffect(() => {
10 Animated.timing(slideAnim, {
11 toValue: isConnected ? -50 : 0,
12 duration: 300,
13 useNativeDriver: true,
14 }).start();
15 }, [isConnected]);
16
17 return (
18 <Animated.View style={[
19 styles.banner,
20 { transform: [{ translateY: slideAnim }] }
21 ]}>
22 <Text style={styles.bannerText}>
23 No Internet Connection
24 </Text>
25 </Animated.View>
26 );
27};
28
29const styles = StyleSheet.create({
30 banner: {
31 position: 'absolute',
32 top: 0,
33 left: 0,
34 right: 0,
35 backgroundColor: '#e74c3c',
36 padding: 10,
37 alignItems: 'center',
38 zIndex: 1000,
39 },
40 bannerText: {
41 color: 'white',
42 fontWeight: 'bold',
43 },
44});
Handling API Calls with Connectivity Check
1const fetchWithConnectivityCheck = async (url, options = {}) => {
2 const state = await NetInfo.fetch();
3
4 if (!state.isConnected) {
5 throw new Error('No internet connection. Please check your network.');
6 }
7
8 try {
9 const response = await fetch(url, {
10 ...options,
11 signal: AbortSignal.timeout(10000), // 10s timeout
12 });
13 return response;
14 } catch (error) {
15 // Re-check connectivity on failure
16 const currentState = await NetInfo.fetch();
17 if (!currentState.isConnected) {
18 throw new Error('Lost internet connection during request.');
19 }
20 throw error;
21 }
22};
23
24// Usage
25try {
26 const response = await fetchWithConnectivityCheck('https://api.example.com/data');
27 const data = await response.json();
28} catch (error) {
29 Alert.alert('Network Error', error.message);
30}
NetInfo Configuration
1// Configure NetInfo behavior
2NetInfo.configure({
3 reachabilityUrl: 'https://clients3.google.com/generate_204',
4 reachabilityTest: async (response) => response.status === 204,
5 reachabilityLongTimeout: 60 * 1000, // 60s for long polling
6 reachabilityShortTimeout: 5 * 1000, // 5s for quick check
7 reachabilityRequestTimeout: 15 * 1000, // 15s timeout per request
8 reachabilityShouldRun: () => true,
9});
The default reachability URL is https://clients3.google.com/generate_204. For apps in China or corporate networks, change this to your own server endpoint.
Common Pitfalls
isInternetReachable is null initially: On first check, isInternetReachable may be null while the reachability test runs. Use state.isInternetReachable ?? false or wait for it to resolve before making decisions.
WiFi connected but no internet: A device can be connected to WiFi without internet access (captive portals, local networks). Check isInternetReachable, not just isConnected, for actual internet availability.
Not unsubscribing the listener: Forgetting to call the unsubscribe function from addEventListener causes memory leaks and state updates on unmounted components. Always return the unsubscribe function in useEffect cleanup.
Missing Pod install on iOS: After installing the npm package, cd ios && pod install is required for native iOS linking. Skipping this causes a build error.
Rapid state changes causing flicker: Network status can toggle rapidly during transitions. Debounce the state updates or add a brief delay before showing offline UI to avoid flickering.
Summary
Use @react-native-community/netinfo for cross-platform network monitoring
NetInfo.fetch() for one-time checks, NetInfo.addEventListener for real-time monitoring
Check both isConnected and isInternetReachable for reliable connectivity detection
Create a custom useNetworkStatus hook for reusable network state
Always unsubscribe listeners in useEffect cleanup to prevent memory leaks
Configure reachabilityUrl for custom environments (corporate networks, China)