A Guide To React Native Offline Support
An introduction to React Native's offline feature and some popular ways to implement it on our apps

react native dev
Search for a command to run...
An introduction to React Native's offline feature and some popular ways to implement it on our apps

react native dev
Did you have an example that can save to do note in database when offline
Is the local IDE dead? Sanket Sahu discusses the rise of 'vibe-coding' and how browser-native tools like RapidNative are reshaping the future of mobile app development.

OpenClaw is a powerful, self-hosted AI assistant that connects to your tools to perform actions. Explore its Gateway architecture, real-world use cases, and security precautions.

Discover how neo-brutalism is shaping 2026 design trends. See how anti-design principles can create distinct, usable, and memorable product experiences.

When code breaks a pipeline, developers have to stop working and figure out why. This blog shows how an AI agent reads the error, finds the fix, and submits it for review all on its own.

GeekyAnts built a 5-agent fraud detection pipeline that makes decisions in under 200ms — 15x cheaper than single-model systems, with full explainability built in.

GeekyAnts Tech Blog
349 posts
GeekyAnts is an AI-powered digital product engineering and consulting company helping startups, enterprises, and Fortune 500 brands build scalable, future-ready digital solutions. Since 2006, we have delivered 800+ successful projects for 550+ global clients across healthcare, BFSI, retail, logistics, education, and enterprise technology. We help businesses accelerate digital transformation through strategy, design, engineering, and AI-led innovation.
In this blog, we will be going through the topic of offline support on React Native and what are the different ways we can go about implementing it on an application. But before we start off, let us first understand what offline support is and why apps need it.
We use a lot of apps in our daily lives and while some of them do not require an active internet connection, most of them do! Some examples of these kinds of apps are Facebook, Twitter, YouTube, etc.
Apps need an active internet connection to communicate with their respective servers and enable user interaction. But what happens to these apps when there is no internet connection? We need to address the fact that apps have a dependency over an active internet connection and there might be a situation where our app might not be able to connect with one. This is where offline support comes in and we can use React Native offline support to handle this interaction smoothly and provide the user with a great user experience.
The most popular methods to achieve offline support in React Native are by implementing usage restrictions, caching, and request queuing.


Caching: Here, we will receive a response from the server and store this data within the local storage of the device. This allows us to retrieve and render the data from the local storage in scenarios where the app is not able to connect to the internet. The download feature that YouTube offers is an example of how caching works.
Request queue: Using this method, we can store all the feature requests made by the user and we can execute them once our app is back online. For example, a note-taking app that has this feature implemented would allow its users to make changes even when there is no active internet connection as it changes are backed up in the server.
Let's get you up to speed! You can find the starter files here. In the above link, you can find a simple app that generates a random user every time the user clicks on the Add User button. We will be using an apisauce library to make external calls. You can refer to the image below to understand this better:

Now let's try to add usage restrictions when our app goes offline.
Dependencies
netinfo to determine whether our app is connected to the internet or not. Refer to the code below:npm i @react-native-community/netinfo
cd ios
pod install
android/build.gradle configuration. Use the code given below to do this:buildscript {
ext {
buildToolsVersion = "28.0.3"
minSdkVersion = 16
compileSdkVersion = 28
targetSdkVersion = 28
# Only using Android Support libraries
supportLibVersion = "28.0.0"
}
Implementation
Let's create a component that takes up the entire screen and notifies the user that the app is currently offline. This component should take up the entire screen space available, such that the user is not able to use any of the app features.
app/components/OfflineNotice.js using the code given below:import React from 'react';
import {View, Text, Image, StyleSheet} from 'react-native';
import {useNetInfo} from '@react-native-community/netinfo';
const OfflineNotice = () => {
const netInfo = useNetInfo();
if (netInfo.type !== 'unknown' && netInfo.isInternetReachable === false)
return (
<View style={styles.container}>
<Image
style={styles.image}
source={require('../assets/images/offline.png')}
/>
<Text style={styles.text}>No Internet Connection</Text>
</View>
);
return null;
};
const styles = StyleSheet.create({
container: {
alignItems: 'center',
justifyContent: 'center',
height: '100%',
width: '100%',
zIndex: 1,
},
image: {
height: 500,
width: 500,
},
text: {
fontSize: 25,
},
});
export default OfflineNotice;
react-native-community/netinfo provides us with a hook called useNetInfo() which returns a hook with the NetInfoState type which can be used to get access to the latest state. We need to wait until netInfo determines the type of connection and even then if our app is not able to connect with the internet we can proceed to notify the user by rendering the OfflineNotice component. Use the code given below:if (netInfo.type !== 'unknown' && netInfo.isInternetReachable === false)
return (
<View style={styles.container}>
<Image
style={styles.image}
source={require('../assets/images/offline.png')}
/>
<Text style={styles.text}>No Internet Connection</Text>
</View>
);
app/App.js using the code given below:import React, {useState} from 'react';
import {StyleSheet, SafeAreaView} from 'react-native';
import LandingScreen from './Screens/LandingScreen';
import userApi from './api/user';
import OfflineNotice from './components/OfflineNotice';
const App = () => {
const [users, setUsers] = useState([]);
const getUser = async () => {
const tempUser = await userApi.getUsers();
setUsers([...users, tempUser]);
};
return (
<>
<OfflineNotice />
<SafeAreaView style={styles.container}>
<LandingScreen getUser={getUser} users={users} />
</SafeAreaView>
</>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
},
});
export default App;

Well, this looks great! Doesn't it? Now, let’s try to implement caching in the next segment.
One thing that we should keep in mind while performing caching is that we should not store any sensitive data in the local storage because React-Native's Async Storage provides us an unencrypted key-value store. Caching can be implemented with or without Redux. Let us first try to implement caching without Redux.
You can find the starter files here. In this link, you can find a simple app that fetches a list of random users every time it is launched. Refer to the image given below:

Now when our app goes offline and if it displays nothing except just a blank screen when we try to refresh or relaunch our app, then it is not a great experience. We can fix this with the help of caching without redux. Refer to the image given below:

To cache without Redux, you need to add the required dependencies with the help of the snippet given below:
npm i @react-native-async-storage/async-storage moment
Implementation
app/Utility/cache.js.timeStamp of the duration which allows us to determine the status of the data when it is being retrieved. If we find that the time difference between the current duration and the timeStamp of the data is more than the allowed TTL(time to live), then we should receive a null. Enter the following code snippet:import AsyncStorage from '@react-native-async-storage/async-storage';
import moment from 'moment';
const prefix = 'cache';
const expiryInMinutes = 5;
const store = async (key, value) => {
const item = {
value,
timeStamp: Date.now(),
};
try {
await AsyncStorage.setItem(prefix + key, JSON.stringify(item));
} catch (err) {
console.log(err);
}
};
const isExpired = item => {
const now = moment(Date.now());
const storedTime = moment(item.timeStamp);
return now.diff(storedTime, 'minutes') > expiryInMinutes;
};
const get = async key => {
try {
const value = await AsyncStorage.getItem(prefix + key);
const item = JSON.parse(value);
if (!item) return null;
if (isExpired(item)) {
await AsyncStorage.removeItem(prefix + key);
return null;
}
return item.value;
} catch (err) {
console.log(err);
}
};
export default {store, get};
app/api/client.js.get method of our apiClient such that if we successfully get a response back from the server, we can store this data within the local storage and then forward it to the components. import {create} from 'apisauce';
import cache from '../utility/cache';
const apiClient = create({
baseURL: 'https://randomuser.me',
});
const get = apiClient.get;
//^ altering the get()
apiClient.get = async (url, params, axiosConfig) => {
const response = await get(url, params, axiosConfig);
if (response.ok) {
await cache.store(url, response.data); //* caching the response
return response;
}
const data = await cache.get(url); //* retrieving the data from the cache
return data ? {ok: true, data} : response;
};
export default apiClient;
You can find the required Redux integrated files here. As in the above segments, this link should provide you with a similar app that fetches a list of random users every time it is launched.
Implementation
redux-persist into our app, since the Redux structure is already set up.app/store/index.js://& REDUX
import {createStore, applyMiddleware} from 'redux';
import {composeWithDevTools} from 'redux-devtools-extension';
//& SAGA
import createSagaMiddleware from '@redux-saga/core';
//& OFFLINE SUPPORT
import {persistStore, persistReducer} from 'redux-persist';
import AsyncStorage from '@react-native-async-storage/async-storage';
import reducers from '../reducer';
import middlewares from '../sagas';
const sagaMiddlewares = createSagaMiddleware();
const persistConfig = {
key: 'root',
storage: AsyncStorage, // local storage
};
const persistedReducer = persistReducer(persistConfig, reducers);
export const store = createStore(
persistedReducer,
composeWithDevTools(applyMiddleware(sagaMiddlewares)),
);
sagaMiddlewares.run(middlewares);
export const persistor = persistStore(store);
PersistGate while passing the persistor as a prop. Enter the following code snippet under index.js:import React from 'react';
import {AppRegistry} from 'react-native';
import {Provider} from 'react-redux';
import App from './app/App';
import {name as appName} from './app.json';
import {store, persistor} from './app/store';
import {PersistGate} from 'redux-persist/integration/react';
const connectedApp = () => {
return (
<Provider store={store}>
<PersistGate persistor={persistor} loading={null}>
<App />
</PersistGate>
</Provider>
);
};
AppRegistry.registerComponent(appName, () => connectedApp);
With that, our caching is done! Yes, it was that simple, all thanks to Redux!
As stated earlier, the best example of this would be to make some changes in our notes while our note app remains offline. As soon as the note app goes back online, it would try to update the changes in the server. Even though it is a great feature to have, this can increase the complexity of our app with problems such as automatic retries, conflict issues, etc., so it is better to avoid it if possible.
We can easily achieve request queuing with the help of the redux-offline library. Redux-offline internally uses NetInfo and redux-persist. Let's see how this is done!
Implementation
npm i redux-offline
store.js:import { applyMiddleware, createStore, compose } from 'redux';
import { offline } from 'redux-offline';
import offlineConfig from 'redux-offline/lib/defaults';
const store = createStore(
reducer,
compose(
applyMiddleware(middleware),
offline(offlineConfig)
)
);
const setUsers = users => ({
type: 'SETUSERS',
payload: users,
meta: {
offline: {
// the network action to save the changes
effect: { url: '/api/save-data', method: 'POST', json: { users } },
// action to dispatch when effect succeeds:
commit: { type: 'SAVE_USERS_COMMIT', meta: { users } },
// action to dispatch if network action fails permanently:
rollback: { type: 'SAVE_USERS_ROLLBACK', meta: { users } }
}
}
});
network action gets called, the commit action will be dispatched to commit the changes that are required. On the other hand, if the app is offline, then redux-offline will wait until the app goes back online, and then the network action will be called.If the network action fails for some reason, even after coming back online then the rollback action will be dispatched and all the changes made in the application's state will be undone. Few services such as Firebase, Amplify, etc. automates the process of request queuing from their end to simplify the development process.
If you are working on the Android platform then you need to make sure to request permission to access the network state in your AndroidManifest.xml:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
To summarise things, there are a few ways to handle your React Native application when the internet connection is not reachable, some of which have been discussed in this article, you can go ahead and pick whichever method suits you. You can even integrate usage restriction and caching to provide a proper smooth offline user experience. Adding this offline support to your application is very essential as you don’t want to leave your users hanging in the mids of an essential task, especially when the internet connection is quite shaky. Because if you don’t add the support, the internet will surely come back on but your users probably won't.
I hope this helped you to get a better understanding of offline support in React Native.
In case this article helped, then make sure to give it a like.
Reach me out: linktr.ee/iambiswanath