React Native

React Native : One Pressable to Rule Them All

While working on a mobile app, you will inevitably have to deal with touch based inputs, for example a press on the screen. As a developer, you surely know the so-far unchallenged component TouchableOpacity and its friends TouchableWithoutFeedback and TouchableHighlight. However, React Native introduced Pressable in July 2020, which is likely to question the status quo. It is THE new wrapper that manages press interactions on its children and which is intended to replace all the touchable components that React Native proposes. But why should you use it? 


Pressable is an all-in-one touchable and proposes even more options

Indeed, with this single component you can basically implement all the features offered by TouchableOpacity, TouchableWithoutFeedback and TouchableHighlight, and even more!

By using a Pressable component with appropriate properties, you can reproduce easily:

 -  the absence of feedback specific to TouchableWithoutFeedback

via GIPHY

 -  the change of opacity proposed by TouchableOpacity

via GIPHY

 

 -  the appearance of the underlay color proposed by TouchableHighlight

via GIPHY

 

But that is not all! Pressable includes additional behaviors that are not offered by touchable components. For instance, it can handle focus and blur events. It also supports web platforms interactions allowing to deal with hovers. These last options were not proposed by the touchable components: thus, it is a big step, especially considering the current state of React Native Web.

 

Pressable is more reliable and future-proof

You surely wonder how this new component is more reliable than the different touchables. The answer comes right from the React Native documentation, on the Pressable page: it uses the Pressability API which is a refactoring of the code behind the touchable components. 

Identical state machine

Touchable Mixin and Pressability API have the same state machines.

 

Indeed, the touchable components are based on the Touchable Mixin and use React.createClass( ). 

But what is a Mixin? It is a way of sharing functions and behaviors between components when composition seems difficult or impossible. It is not technically deprecated but Facebook does not recommend its use because it can introduce some problems. 

Mixins entail implicit dependencies between your components and can make code-reuse and modifications very complex for developers. There are also some issues with methods naming. Mixins do not allow two methods to have the same name. This can hinder naming best practices and result in awkward method names. It is even worse if you use a third party package for some mixins and their authors decide some day to change the name of one method : it can be a breaking change for your code!

 

If you want to learn more about Mixins and why Facebook recommends to avoid them, you can read this interesting blog post: 

https://reactjs.org/blog/2016/07/13/mixins-considered-harmful.html

 

The Pressability refactoring solves the problems caused by the mixin's usage and also enables composition by modern functional React components, either implemented as ES6 classes or through the use of React Hooks. With this refactoring and the outstanding banners on the different touchable components' pages, React Native clearly promotes Pressable as the future one and only touch based input wrapper.

react-native-pressable-promotion-banner

++pre>++code>Note: if you do not want to change your coding habits and do not need the additional features of Pressable, do not worry.
React Native has also refactored the touchable components, without modifying their inherent behaviors, to make them use the Pressability API instead of the Touchable Mixin.++/pre>

 

How to use Pressable?

If you want to use Pressable in your project, it will require at least React Native 0.63 version or Expo SDK 40 version. 

Then you can start using Pressable in minutes! 

 

 -  Pressable as a TouchableWithoutFeedback: 

++pre>import React, { useState } from 'react';
import { SafeAreaView, View, Text, Pressable } from 'react-native';

const App = () => {
  const [pressablePressed, setPressablePressed] = useState(0);
  return (
<SafeAreaView>
<View style={{justifyContent: 'center', alignItems: 'center'}}>
<Pressable
            onPress={() => setPressablePressed(pressablePressed + 1 )}
style={() => [{ backgroundColor: '#0A369D'}]} >
<View style={{ alignItems: 'center', padding: 10}}>
<Text style={{color: '#FFFFFF'}}>Pressable</Text>
</View>
</Pressable>
</View>
</SafeAreaView>
  )
}

export default App;++/pre>

 

 -  Pressable as a TouchableOpacity: 

++pre>import React, { useState } from 'react';
import {  {    SafeAreaView, View, Text, Pressable } from 'react-native';

const App = () => {
  const [pressablePressed, setPressablePressed] = useState(0);
  return (
     <SafeAreaView>
       <View style={{justifyContent: 'center', alignItems: 'center'}}>
         <Pressable
           onPress={() => setPressablePressed(pressablePressed + 1 )}
           style={({ pressed }) => [
             { backgroundColor: '#0A369D',
               opacity: pressed
                  ? 0.5
                  : 1,
             }                 ]} >
             <View style={{ alignItems: 'center', padding: 10}}>
                <Text style={{color: '#FFFFFF'}}>Pressable</Text>
             </View>
         </Pressable>
       </View>
     </SafeAreaView>
  )
}

export default App;++/pre>

 

 -  Pressable as a TouchableHighlight: 

++pre>import React, { useState } from 'react';
import {  { SafeAreaView, View, Text, Pressable } from 'react-native';

const App = () => {
  const [pressablePressed, setPressablePressed] = useState(0);
  return (
     <SafeAreaView>
       <View style={{justifyContent: 'center', alignItems: 'center'}}>
         <Pressable
            onPress={() => setPressablePressed(pressablePressed + 1 )}
            style={({ pressed }) => [
              { backgroundColor: pressed
                   ? '#D33F49'
                   : '#0A369D',
                opacity: pressed
                   ? 0.5
                   : 1,
              }                 ]} >
             <View style={{ alignItems: 'center', padding: 10}}>
               <Text style={{color: '#FFFFFF'}}>Pressable</Text>
             </View>
          </Pressable>
       </View>
     </SafeAreaView>
  )
}

export default App;++/pre>

CONCLUSION

With this refactoring, React Native is cleaning its code and proposes a more reliable press-interactions wrapper that replaces three other components. It is a good solution to harmonize your code and stop wondering why you should use TouchableOpacity instead of TouchableHighlight. Thus, I highly recommend that you to start using it, if it is not already done! ?

 

If you have any anecdotes or questions, you can contact me on twitter: @jamin_emma 

 

Sincere thanks to Mr Timothy Yung, principal contributor of the Pressability API, for taking the time to discuss about this topic. 

Développeur mobile ?

Rejoins nos équipes