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 continuing my educational coding exercise, developing a new photo sharing app. Recently, I completed my user authentication and registration process and I’m now quite happy with it, so I moved on to taking photographs. I’ve got an activity with a toolbar and a floating action button:
A quick recap - we’ve got three identity providers integrated into our app, set up an Azure Functions App in our backend using ARM, and we’ve set up authentication on that function app. We’ve also swapped our identity provider authentication token for an Azure App Service authentication token so we can use it on our backend. Now it’s time to consider the actual Azure Function for registration.
We are almost at the end of “registration and authentication” - and it’s been a seriously long way, which just goes to show the amount of complexity in the subject. Thus far, we’ve authenticated with Facebook, Google, and Microsoft, handled silent login and configured the backend resources. In the last article, we configured the backend resources to handle authentication, allowing us to swap a social identity provider token with a ZUMO token that we can use for further authentication.