Модальные окна и оверлеи
Модалки — экраны, которые появляются поверх. Могут быть встроенными в навигацию или кастомными.
Модалка в навигации
<Stack.Screen
name="Modal"
component={ModalScreen}
options={{
presentation: 'modal',
animation: 'slide_from_bottom',
}}
/>
presentation:
'card'— обычный стек'modal'— модалка со свайпом вниз'transparentModal'— прозрачный фон'fullScreenModal'— полный экран без свайпа'formSheet'— как в iOS 15+ (маленькая модалка)'containedModal'— модалка внутри родителя
Открытие
navigation.navigate('Modal');
Закрытие
navigation.goBack();
Или свайпом вниз (для modal).
React Native Modal
Кастомная модалка поверх всего:
import { Modal } from 'react-native';
<Modal
visible={isVisible}
animationType="slide" // 'slide' | 'fade' | 'none'
transparent
onRequestClose={() => setVisible(false)}
statusBarTranslucent
>
<View style={styles.overlay}>
<View style={styles.content}>
<Text>Модальное окно</Text>
<Pressable onPress={() => setVisible(false)}>
<Text>Закрыть</Text>
</Pressable>
</View>
</View>
</Modal>
overlay:
const styles = StyleSheet.create({
overlay: {
flex: 1,
backgroundColor: 'rgba(0,0,0,0.5)',
justifyContent: 'center',
alignItems: 'center',
},
content: {
backgroundColor: '#fff',
borderRadius: 16,
padding: 24,
width: '80%',
},
});
Bottom Sheet
Современный стандарт для модалок снизу:
npx expo install @gorhom/bottom-sheet
import BottomSheet, { BottomSheetView } from '@gorhom/bottom-sheet';
import { useRef, useMemo } from 'react';
function Sheet() {
const ref = useRef<BottomSheet>(null);
const snapPoints = useMemo(() => ['25%', '50%', '90%'], []);
return (
<BottomSheet ref={ref} index={-1} snapPoints={snapPoints}>
<BottomSheetView>
<Text>Содержимое</Text>
</BottomSheetView>
</BottomSheet>
);
}
// открыть
ref.current?.expand();
Alert как модалка
Alert.alert(
'Удалить?',
'Это действие нельзя отменить',
[
{ text: 'Отмена', style: 'cancel' },
{ text: 'Удалить', style: 'destructive', onPress: () => delete() },
]
);
ActionSheet
Меню действий снизу:
import { ActionSheetIOS, Platform } from 'react-native';
if (Platform.OS === 'ios') {
ActionSheetIOS.showActionSheetWithOptions(
{
options: ['Отмена', 'Поделиться', 'Копировать', 'Удалить'],
destructiveButtonIndex: 3,
cancelButtonIndex: 0,
},
(index) => {
if (index === 1) share();
if (index === 2) copy();
if (index === 3) remove();
}
);
}
Для Android — @expo/react-native-action-sheet.
Кастомный ActionSheet
Часто делают свой для единообразия:
function ActionSheet({ actions, visible, onClose }: ActionSheetProps) {
return (
<Modal visible={visible} transparent animationType="slide" onRequestClose={onClose}>
<Pressable style={styles.backdrop} onPress={onClose}>
<View style={styles.sheet}>
{actions.map((action) => (
<Pressable
key={action.label}
onPress={() => { action.onPress(); onClose(); }}
style={styles.item}
>
<Text style={action.destructive ? styles.destructive : styles.text}>
{action.label}
</Text>
</Pressable>
))}
</View>
</Pressable>
</Modal>
);
}
Toast
import Toast from 'react-native-toast-message';
Toast.show({
type: 'success',
text1: 'Сохранено',
position: 'bottom',
});
Если ты уже знаешь React
В вебе — <dialog>, порталы. В React Native — Modal, навигационные модалки, bottom sheet.
Итоги
presentation: 'modal'для навигационных модалокModalдля кастомных@gorhom/bottom-sheetдля bottom sheetAlert.alertдля простых диалоговActionSheetдля меню действий- Toast для уведомлений