React Native Community NetInfo is the most reliable library for monitoring network connectivity in React Native applications. This comprehensive guide covers everything from basic setup to advanced implementation patterns, helping you build robust offline-capable apps.
1. Understanding React Native NetInfo
NetInfo is a React Native library that provides information about the device's network connection status and type. Originally part of React Native core, it was moved to the community to enable faster updates and better platform support.
- Real-time network status monitoring
- Connection type detection (WiFi, Cellular, etc.)
- Internet reachability testing
- Cross-platform support (iOS, Android, Web, macOS, Windows)
- TypeScript support
- Configurable reachability testing
Installation and Setup
Install the library using npm or yarn:
# Using npm
npm install --save @react-native-community/netinfo
# Using yarn
yarn add @react-native-community/netinfo
For React Native 0.60+, the library auto-links. For iOS, run pod install:
# iOS only
cd ios && npx pod-install
2. Basic Usage Patterns
Using the useNetInfo Hook
The simplest way to access network information is through the useNetInfo hook:
import { useNetInfo } from '@react-native-community/netinfo';
import { View, Text } from 'react-native';
function NetworkStatus() {
const netInfo = useNetInfo();
return (
<View>
<Text>Type: {netInfo.type}</Text>
<Text>Is Connected: {netInfo.isConnected?.toString()}</Text>
<Text>Is Internet Reachable: {netInfo.isInternetReachable?.toString()}</Text>
{netInfo.type === 'wifi' && (
<Text>WiFi SSID: {netInfo.details?.ssid || 'Unknown'}</Text>
)}
{netInfo.type === 'cellular' && (
<Text>Carrier: {netInfo.details?.carrier || 'Unknown'}</Text>
)}
</View>
);
}
Event-Based Monitoring
For more control, use the addEventListener method:
import { useEffect, useState } from 'react';
import NetInfo from '@react-native-community/netinfo';
function useNetworkMonitor() {
const [networkState, setNetworkState] = useState(null);
useEffect(() => {
// Subscribe to network state updates
const unsubscribe = NetInfo.addEventListener(state => {
console.log('Connection type:', state.type);
console.log('Is connected:', state.isConnected);
setNetworkState(state);
});
// Get initial state
NetInfo.fetch().then(state => {
setNetworkState(state);
});
// Cleanup subscription
return () => unsubscribe();
}, []);
return networkState;
}
One-time Network Check
For checking network status on-demand:
import NetInfo from '@react-native-community/netinfo';
// Check current network state
async function checkNetworkStatus() {
const state = await NetInfo.fetch();
if (state.isConnected) {
console.log('Device is online');
if (state.isInternetReachable) {
console.log('Internet is reachable');
} else {
console.log('Connected to network but no internet');
}
} else {
console.log('Device is offline');
}
return state;
}
// Check specific network interface
async function checkWiFiStatus() {
const wifiState = await NetInfo.fetch('wifi');
console.log('WiFi SSID:', wifiState.details?.ssid);
console.log('WiFi strength:', wifiState.details?.strength);
}
3. Advanced Configuration
Custom Reachability Configuration
Configure custom reachability testing for better reliability:
import NetInfo from '@react-native-community/netinfo';
// Configure NetInfo with custom settings
NetInfo.configure({
reachabilityUrl: 'https://clients3.google.com/generate_204',
reachabilityTest: async (response) => response.status === 204,
reachabilityLongTimeout: 60 * 1000, // 60s
reachabilityShortTimeout: 5 * 1000, // 5s
reachabilityRequestTimeout: 15 * 1000, // 15s
reachabilityShouldRun: () => true,
shouldFetchWiFiSSID: true, // iOS only - requires proper permissions
useNativeReachability: false
});
Isolated Instance Usage
Use isolated instances for different configurations:
import { useNetInfoInstance } from '@react-native-community/netinfo';
function IsolatedNetworkMonitor() {
const config = {
reachabilityUrl: 'https://api.myapp.com/health',
reachabilityTest: async (response) => {
const data = await response.json();
return data.status === 'ok';
},
reachabilityShortTimeout: 3000,
};
const { netInfo, refresh } = useNetInfoInstance(false, config);
const handleRefresh = () => {
refresh().then(state => {
console.log('Refreshed network state:', state);
});
};
return (
<View>
<Text>Connection: {netInfo.type}</Text>
<Button title="Refresh" onPress={handleRefresh} />
</View>
);
}
4. Real-World Implementation Patterns
Offline-First Architecture
Build a robust offline-first app architecture:
import { useNetInfo } from '@react-native-community/netinfo';
import AsyncStorage from '@react-native-async-storage/async-storage';
function useOfflineCapability() {
const netInfo = useNetInfo();
const [offlineActions, setOfflineActions] = useState([]);
// Queue actions when offline
const queueOfflineAction = async (action) => {
if (!netInfo.isInternetReachable) {
const stored = await AsyncStorage.getItem('offlineActions');
const actions = stored ? JSON.parse(stored) : [];
actions.push({ ...action, timestamp: Date.now() });
await AsyncStorage.setItem('offlineActions', JSON.stringify(actions));
setOfflineActions(actions);
}
};
// Process queued actions when back online
useEffect(() => {
if (netInfo.isInternetReachable && offlineActions.length > 0) {
processOfflineActions();
}
}, [netInfo.isInternetReachable]);
const processOfflineActions = async () => {
const stored = await AsyncStorage.getItem('offlineActions');
if (!stored) return;
const actions = JSON.parse(stored);
for (const action of actions) {
try {
await executeAction(action);
} catch (error) {
console.error('Failed to execute offline action:', error);
}
}
await AsyncStorage.removeItem('offlineActions');
setOfflineActions([]);
};
return { queueOfflineAction, isOnline: netInfo.isInternetReachable };
}
Smart Data Synchronization
Implement intelligent sync based on connection type:
import { useNetInfo } from '@react-native-community/netinfo';
function useSmartSync() {
const netInfo = useNetInfo();
const syncData = async (priority = 'normal') => {
if (!netInfo.isInternetReachable) {
console.log('No internet connection, skipping sync');
return;
}
// Adjust sync behavior based on connection type
let syncConfig = {
batchSize: 100,
enableImages: true,
enableVideos: true,
timeout: 30000,
};
if (netInfo.type === 'cellular') {
if (netInfo.details?.isConnectionExpensive) {
// Reduce data usage on expensive connections
syncConfig = {
batchSize: 20,
enableImages: false,
enableVideos: false,
timeout: 15000,
};
}
}
if (netInfo.type === 'wifi') {
// Full sync on WiFi
syncConfig.batchSize = 500;
}
// Prioritize critical data
if (priority === 'high') {
return await syncCriticalData(syncConfig);
}
return await syncAllData(syncConfig);
};
return { syncData, connectionType: netInfo.type };
}
Connection Quality Monitoring
Monitor and adapt to connection quality:
import { useNetInfo } from '@react-native-community/netinfo';
function useConnectionQuality() {
const netInfo = useNetInfo();
const [quality, setQuality] = useState('unknown');
useEffect(() => {
if (!netInfo.isConnected) {
setQuality('offline');
return;
}
if (netInfo.type === 'wifi') {
const strength = netInfo.details?.strength;
if (strength && strength > 75) {
setQuality('excellent');
} else if (strength && strength > 50) {
setQuality('good');
} else {
setQuality('poor');
}
} else if (netInfo.type === 'cellular') {
const generation = netInfo.details?.cellularGeneration;
switch (generation) {
case '5g':
setQuality('excellent');
break;
case '4g':
setQuality('good');
break;
case '3g':
setQuality('fair');
break;
case '2g':
setQuality('poor');
break;
default:
setQuality('unknown');
}
}
}, [netInfo]);
const getImageQuality = () => {
switch (quality) {
case 'excellent':
return 'high';
case 'good':
return 'medium';
case 'fair':
case 'poor':
return 'low';
default:
return 'low';
}
};
return { quality, getImageQuality };
}
5. Best Practices and Performance Tips
Optimize Listener Management
Properly manage event listeners to avoid memory leaks:
import { useEffect, useRef } from 'react';
import NetInfo from '@react-native-community/netinfo';
function useNetworkListener(callback) {
const callbackRef = useRef(callback);
callbackRef.current = callback;
useEffect(() => {
let unsubscribe;
const setupListener = async () => {
// Get initial state
const initialState = await NetInfo.fetch();
callbackRef.current(initialState);
// Subscribe to changes
unsubscribe = NetInfo.addEventListener(state => {
callbackRef.current(state);
});
};
setupListener();
return () => {
if (unsubscribe) {
unsubscribe();
}
};
}, []);
}
Debounce Network State Changes
Prevent excessive API calls during network fluctuations:
import { useState, useEffect, useRef } from 'react';
import { useNetInfo } from '@react-native-community/netinfo';
function useDebouncedNetInfo(delay = 1000) {
const netInfo = useNetInfo();
const [debouncedNetInfo, setDebouncedNetInfo] = useState(netInfo);
const timeoutRef = useRef();
useEffect(() => {
if (timeoutRef.current) {
clearTimeout(timeoutRef.current);
}
timeoutRef.current = setTimeout(() => {
setDebouncedNetInfo(netInfo);
}, delay);
return () => {
if (timeoutRef.current) {
clearTimeout(timeoutRef.current);
}
};
}, [netInfo, delay]);
return debouncedNetInfo;
}
Handle iOS Background Limitations
Account for iOS limitations when switching WiFi networks:
import { useEffect } from 'react';
import { AppState, Platform } from 'react-native';
import NetInfo from '@react-native-community/netinfo';
function useIOSNetworkRefresh() {
useEffect(() => {
if (Platform.OS !== 'ios') return;
const handleAppStateChange = async (nextAppState) => {
if (nextAppState === 'active') {
// Refresh network state when app becomes active
const newState = await NetInfo.refresh();
console.log('Refreshed network state on iOS:', newState);
}
};
const subscription = AppState.addEventListener('change', handleAppStateChange);
return () => subscription?.remove();
}, []);
}
6. Testing Strategies
Mocking NetInfo for Tests
Set up proper mocking for unit tests:
// jest.setup.js
import mockRNCNetInfo from '@react-native-community/netinfo/jest/netinfo-mock.js';
jest.mock('@react-native-community/netinfo', () => mockRNCNetInfo);
// Custom mock for specific test scenarios
export const createNetInfoMock = (initialState) => ({
addEventListener: jest.fn(() => jest.fn()),
fetch: jest.fn(() => Promise.resolve(initialState)),
refresh: jest.fn(() => Promise.resolve(initialState)),
configure: jest.fn(),
useNetInfo: jest.fn(() => initialState),
});
Integration Testing
Test network-dependent features:
// NetworkComponent.test.js
import { render, waitFor } from '@testing-library/react-native';
import NetInfo from '@react-native-community/netinfo';
import NetworkComponent from './NetworkComponent';
// Mock different network states
const mockNetworkStates = {
online: {
type: 'wifi',
isConnected: true,
isInternetReachable: true,
details: { ssid: 'TestWiFi' }
},
offline: {
type: 'none',
isConnected: false,
isInternetReachable: false,
details: null
}
};
describe('NetworkComponent', () => {
beforeEach(() => {
jest.clearAllMocks();
});
it('should display online status when connected', async () => {
NetInfo.useNetInfo.mockReturnValue(mockNetworkStates.online);
const { getByText } = render(<NetworkComponent />);
await waitFor(() => {
expect(getByText('Connected to TestWiFi')).toBeTruthy();
});
});
it('should show offline message when disconnected', async () => {
NetInfo.useNetInfo.mockReturnValue(mockNetworkStates.offline);
const { getByText } = render(<NetworkComponent />);
await waitFor(() => {
expect(getByText('No internet connection')).toBeTruthy();
});
});
});
7. Common Pitfalls and Solutions
- Memory Leaks: Always unsubscribe from event listeners
- False Positives: isConnected doesn't guarantee internet access
- iOS Simulator Issues: Test on real devices for accurate results
- Background Limitations: iOS apps may not receive network events in background
- Permission Requirements: WiFi SSID requires location permissions on Android
Handle Edge Cases
function RobustNetworkHandler() {
const [networkState, setNetworkState] = useState({
isOnline: false,
hasInternet: false,
connectionType: 'unknown'
});
useEffect(() => {
const updateNetworkState = (state) => {
setNetworkState({
isOnline: state.isConnected ?? false,
hasInternet: state.isInternetReachable ?? false,
connectionType: state.type || 'unknown'
});
};
// Handle initial state
NetInfo.fetch()
.then(updateNetworkState)
.catch((error) => {
console.error('Failed to fetch initial network state:', error);
// Provide fallback state
setNetworkState({
isOnline: false,
hasInternet: false,
connectionType: 'unknown'
});
});
const unsubscribe = NetInfo.addEventListener(updateNetworkState);
return unsubscribe;
}, []);
return networkState;
}
8. Performance Optimization
Selective Updates
Optimize re-renders by selecting specific network properties:
import { useMemo } from 'react';
import { useNetInfo } from '@react-native-community/netinfo';
// Only re-render when connection status changes
function useConnectionStatus() {
const netInfo = useNetInfo();
return useMemo(() => ({
isConnected: netInfo.isConnected,
isInternetReachable: netInfo.isInternetReachable
}), [netInfo.isConnected, netInfo.isInternetReachable]);
}
// Only re-render when connection type changes
function useConnectionType() {
const netInfo = useNetInfo();
return useMemo(() => netInfo.type, [netInfo.type]);
}
Lazy Network Checks
Implement lazy loading for network-dependent features:
function LazyNetworkFeature({ children }) {
const netInfo = useNetInfo();
const [shouldLoad, setShouldLoad] = useState(false);
useEffect(() => {
if (netInfo.isInternetReachable && !shouldLoad) {
// Only load feature when internet is available
setShouldLoad(true);
}
}, [netInfo.isInternetReachable, shouldLoad]);
if (!shouldLoad) {
return <OfflineMessage />;
}
return children;
}
Conclusion
React Native Community NetInfo is an essential tool for building robust, network-aware mobile applications. By following the patterns and best practices outlined in this guide, you can create apps that gracefully handle network changes, provide excellent offline experiences, and adapt to different connection qualities.
Remember to always test your network-dependent features on real devices and various network conditions. Consider implementing offline-first architecture patterns for critical app functionality, and always provide clear feedback to users about their connection status.
The library continues to evolve with new features and improvements, so stay updated with the latest releases and community contributions for the best possible user experience.
🚀 Ready to catch UI issues before your users do?
Use Viewlytics to automatically capture and analyze your app's UI across real devices. Our AI-powered platform helps you identify visual bugs, layout issues, and inconsistencies before they impact user experience.
Start UI Testing with Viewlytics