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
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:
export type MoodOptionType = { emoji: string; description: string;};
Now let's import this type in MoodPicker
:
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:
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[] = [
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:
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> );
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:
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> );
backgroundColor: '#454C73', borderColor: '#fff', },+ descriptionText: {+ color: '#454C73',+ fontWeight: 'bold',+ fontSize: 10,+ textAlign: 'center',+ },});