Implementing swipe-right on a React Native FlatList
August 07, 2017
6 minute read
I’m progressing on my “master-detail” pattern for a react-native app. The actual implementation of master-detail is shockingly simple (more on that later). However, I bumped into some specific issues when I was implementing it. The first of these was covered last time – how to detect orientation changes in React Native. The next is this. How do I implement swipe-right so that I can add a swipe-to-delete function to a FlatList.
Let me explain a little further. The latest edition of React Native has updated the list handling. ListView is (or will be) deprecated. A bunch of new list handling methods come in, among them the FlatList, SectionList and VirtualizedList. This is great. I no longer have to implement a data source. All I have to do is pass the data I want to render to the FlatList and a rendering function and I am done.
There is also another component – the Swipeout – that implements swiping. However, it does it for ListView, which is deprecated. So no joy there. Or so I thought. It’s actually possible, but with a huge set of provisos.
Let’s start with the setup. I have two components – a NoteList.js component that renders the list, and a NoteListItem.js that renders the NoteListItem. I want a few events to fire on the NoteList.js:
onSelectItem(item) will fire when the item is pressed.
onDeleteItem(item) will fire when the item is swipe-right deleted.
onAddItem() will fire when the plus item in the status bar is pressed.
These will then effect a scene change or a data update as needed. There are a couple of rules to keep in mind:
Touchable events must have a native item as their direct child (or pass on setNativeProps).
Swipeout requires the rowId to handle open/close properly (so only one swipe drawer is open at any given time).
The first rule means you need to handle an onPress event in the NoteListItem renderer which is then picked up by the list item. Here is my NoteListItem.js script:
Note how I pass in the onPress event handler (with a default, in case you don’t do this). I also wrap the View (which is a native component) in the TouchableHighlight so that my entire view is clickable. This makes the entire row clickable if we define an onPress event handler.
Let’s take a look at the setup of the NoteList.js class first.
This is all fairly basic FlatList code. If you use a simple application, like this:
Then you should be able to see the three items and click on them. A debug message will appear in the debug console. In addition, you can click on the plus sign in the status bar and get the onAddItem debug message.
Now, let’s consider swiping. All this work is done in the NoteList.js component. I’m going to use react-native-swipeout to handle swiping. Firstly, I need to understand what row is currently showing the swipe-right drawer. To do this, add an activeRow element to the component state:
Next, ensure that the FlatList is re-rendered when the state is changed. This is handled in the FlatList props:
This state is changed on two occasions. Firstly, when the user swipes right, I’m going to call event handler this.onSwipeOpen(). Then, when the swipe-right drawer closes, I’m going to call this.onSwipeClose(). I’ll use these methods to control the state:
The important functionality is within the onSwipeClose() method. This will only reset the state to null (meaning nothing is selected) when the closed item is the currently active element. This is important because Swipeout calls the onClose event handler (which is this method) for all sorts of events, most of which do not actually indicate a new swipe.
Finally, let’s take a look at how this is rendered in the renderItem() method:
The main item to note here is that the rowId is filled in by the index of the data object passed to FlatList, which starts at 0 and goes up from there. The onOpen() and onClose() event handlers are wired to the new onSwipeOpen() and onSwipeClose() methods, and the close flag is set so that the drawer is closed if the active row does not match.
If you implement this code, you will note the following:
Pressing a row calls onSelectItem().
Swiping right will open the swipe-right drawer with the Delete button in it.
Swiping right on another row will cause the original swipe-right drawer to close.
Pressing the delete button calls onDeleteItem().
Hopefully, the next blog post will be about the master-detail pattern in React Native. Until then, I hope this helps implementing awesome lists.
I’m currently working on some automation within Azure to deploy a hub-spoke web application. This web application authenticates with Entra ID using an App Registration and Role-Based Access Controls (RBAS) using App Roles. So, I need to create an app registration, enterprise app, and create the app roles.
One of the persistent questions I get asked about Azure Mobile Apps is how to support older tables. Let’s say you have an older application that was never designed for mobile applications. It likely has a model like this:
If you are an Azure developer, you likely spin up an application, do some work, then shut it down again. However, shutting down resources and deleting them has an order to them. If your service is network isolated (in a virtual network), then you can’t delete the application until the private endpoints are shut down. Budgets don’t get deleted with the resource group. Diagnostic settings can’t be deleted if the resource no longer exists. There is an order you should do things:
I work a lot with Azure API Management, which means I turn up and down services quite a few times a day. Azure API Management has an awesome feature that prevents you from accidentally deleting a service, called soft-delete. Instead of immediately deleting the service, it marks it as soft deleted and purges it later on. Unfortunately, that means that you can’t immediately reuse that service name. In production, this is a great thing to have. In development, it turns into a pain. That’s b...
Leave a comment