Handling Offline Actions in React Native
A few weeks ago I wrote about building offline first react native apps and left the post with a question — “How would you handle actions taken while offline and sync them with the server the next time the user uses the app while online?”
Today we’ll explore one, simple, answer to that question. It’s an extremely basic app. We press a button and fetch a person from the Star Wars API. When we press the button we increment the person index by one (so we don’t fetch the same person over and over) and if the user is offline then we put the requests into our redux store and, when the user’s connection is restored, we make all of the stored requests.
If you’re reading this and thinking there are a bunch of cases I’m ignoring, you’re right. This is the most basic it can be — hopefully serving as a starting point.
Since this post is a bit more advanced I’m going to be making some assumptions on what you know — a basic familiarity with Redux and React Native. You can access the full project on GitHub. Some of the prerequisite info has been covered in my previous post. Here’s an overview of the packages we’ll be using.
- lodash — it makes life easy
- react-native-elements — for basic styling
- react-native-vector-icons — icons
- react-redux — make using redux easy with react (native)
- redux-persist — to persist our store to disk
- redux-thunk — async redux actions
Now to save time I’m going to skip setting up the app — the list component, making the request, and basic redux config. All the changes to a default React Native app can be found in this Gist. With these changes we’re able to press the button and add the person to a list but it doesn’t have any offline functionality.
At the core of this we’ll be using the NetInfo API to detect whether or not the user has an internet connection. You can drill down into the details about the connection type with this api but we only care about whether or not the user is connected.
In order to track this we’ll be listening to the connection status and, upon change, writing the current status to our redux store.
With that in mind, let’s get to coding. First we’ll create an action that our component can call when the status changes.
And we’ll set up our reducer to handle that change and update the store accordingly.
So now we need to listen to the network change. We’re also going to change the icon depending on the connection status AND make sure we subscribe to these pieces of data from our redux connect function.
Make sure that you remove event listeners upon unmount to avoid memory issues.
Cool! So now our redux store will update as our connection state does and we can use that when we’re making remote requests. Speaking of which, let’s update our requestPerson so that it only makes the fetch when connected.
Now, as you see above, when we don’t have a connection we’re adding the endpoint to the store so we can fetch it later.
Upon connecting we’re basically doing the same thing as requestPerson but it’s a bit more basic.
- We don’t need to increment the number
- It will only be called when we’re connected (there are some cases where this might not be true but that’s out of scope) so we don’t need to check if we’re connected.
With those considerations in mind we’ll create a new action called requestPersonByUrl in our actions file.
One addition there that we’re not yet handling in our reducer is the REMOVE_FROM_ACTION_QUEUE — let’s update the reducer to handle that. I’m using lodash to remove the url easily, regardless of it’s location in the array.
Now to actually call all these functions! We’ll have to do this in the NameList component. It’s actually pretty simple — in our _handleConnectionChange we’ll check if we’re connected and if there are any url’s in our actionQueue if yes, then we’ll make the necessary requests.
Let’s check out what we’ve actually built. It’s simple but lays a solid foundation.
Did you find this helpful? Sign up for my email list — I help people become professional React Native developers.