Skip to main content

Pressable and useState

Pressable is a relatively new component, introduced in React Native 0.63. It is a more versatile alternative to the TouchableOpacity / TouchableHighlight / TouchableWithoutFeedback we're already familiar with. The Touchable components will be deprecated in future versions of React Native, so it is recommended to use Pressable instead.

The Pressable component gives you fine grained control over the pressed state. Unlike TouchableOpacity, Pressable does not have any styles applied for the pressed state, but if you wanted, you could achieve the same effect by applying the pressed style yourself:

Example component: Pressable styled as TouchableOpacity

src/components/PressableArea.tsx
import React from 'react';import { Pressable, PressableProps } from 'react-native';
export const PressableArea: React.FC<PressableProps> = ({  children,  style,  ...rest}) => {  return (    <Pressable      {...rest}      style={(args) => {        const appliedStyle = typeof style === 'function' ? style(args) : style;        if (args.pressed) {          return [appliedStyle, { opacity: 0.9 }];        }        return appliedStyle;      }}    >      {children}    </Pressable>  );};

useState is one of the the core React Hooks we'll be using to store the selected value.

Let's start by creating a TypeScript type for the emoji option.

Create a new file in the src directory and call it types.ts - this will hold all the shared types for our app.

Open the file and add a type for the mood option:

src/types.ts
export type MoodOptionType = {  emoji: string;  description: string;};

Now let's import this type in MoodPicker:

src/components/MoodPicker.tsx
 import React from 'react';-import { View, Text, StyleSheet } from 'react-native';+import { View, Text, StyleSheet, Pressable } from 'react-native';+import { MoodOptionType } from '../types';-const moodOptions = [+const moodOptions: MoodOptionType[] = [   { emoji: '๐Ÿง‘โ€๐Ÿ’ป', description: 'studious' },   { emoji: '๐Ÿค”', description: 'pensive' },   { emoji: '๐Ÿ˜Š', description: 'happy' },

and let's create a useState variable to store the mood option in:

const [selectedMood, setSelectedMood] = React.useState<MoodOptionType>();

Notice we've added the option type in <> and if we hover over selectedMood, TypeScript will tell us that this value is wither of type MoodOptionType or undefined (since we don't give it an initial value).

Next let's wrap each of the emoji in a Pressable and use a useState to store the currently selected option:

src/components/MoodPicker.tsx
 import React from 'react';-import { View, Text, StyleSheet } from 'react-native';+import { View, Text, StyleSheet, Pressable } from 'react-native'; import { MoodOptionType } from '../types'; const moodOptions: MoodOptionType[] = [
src/components/MoodPicker.tsx
   return (     <View style={styles.moodList}>       {moodOptions.map(option => (-        <Text key={option.emoji} style={styles.moodText}>-          {option.emoji}-        </Text>+        <Pressable onPress={() => setSelectedMood(option)} key={option.emoji}>+          <Text style={styles.moodText}>{option.emoji}</Text>+        </Pressable>       ))}     </View>   );

Let's give the currently selected mood a highlighted background so we could tell which mood is selected:

src/components/MoodPicker.tsx
   return (     <View style={styles.moodList}>       {moodOptions.map(option => (-        <Text key={option.emoji} style={styles.moodText}>-          {option.emoji}-        </Text>+        <Pressable+          onPress={() => setSelectedMood(option)}+          key={option.emoji}+          style={[+            styles.moodItem,+            option.emoji === selectedMood?.emoji+              ? styles.selectedMoodItem+              : undefined,+          ]}>+          <Text style={styles.moodText}>{option.emoji}</Text>+        </Pressable>       ))}     </View>   );
src/components/MoodPicker.tsx
    justifyContent: 'space-between',    padding: 20,  },+  moodItem: {+    width: 60,+    height: 60,+    justifyContent: 'center',+    alignItems: 'center',+    borderRadius: 30,+    marginBottom: 5,+  },+  selectedMoodItem: {+    borderWidth: 2,+    backgroundColor: '#454C73',+    borderColor: '#fff',+  },});

And finally, we'll add the description text for the selected item:

src/components/MoodPicker.tsx
   return (     <View style={styles.moodList}>       {moodOptions.map(option => (-        <Pressable-          onPress={() => setSelectedMood(option)}-          key={option.emoji}-          style={[-            styles.moodItem,-            option.emoji === selectedMood?.emoji-              ? styles.selectedMoodItem-              : undefined,-          ]}>-          <Text style={styles.moodText}>{option.emoji}</Text>-        </Pressable>+        <View>+          <Pressable+            onPress={() => setSelectedMood(option)}+            key={option.emoji}+            style={[+              styles.moodItem,+              option.emoji === selectedMood?.emoji+                ? styles.selectedMoodItem+                : undefined,+            ]}>+            <Text style={styles.moodText}>{option.emoji}</Text>+          </Pressable>+          <Text style={styles.descriptionText}>+            {selectedMood?.emoji === option.emoji ? option.description : ' '}+          </Text>+        </View>       ))}     </View>   );
src/components/MoodPicker.tsx
    backgroundColor: '#454C73',    borderColor: '#fff',  },+  descriptionText: {+    color: '#454C73',+    fontWeight: 'bold',+    fontSize: 10,+    textAlign: 'center',+  },});
iOS select moodAndroid select mood