Введение
React Native остаётся одной из самых популярных технологий для кроссплатформенной мобильной разработки в 2026 году. Согласно опросу Stack Overflow 2025, его используют 38% профессиональных разработчиков, а новые версии (0.76+ с архитектурой New Architecture) сделали фреймворк ещё быстрее. Но даже с современными инструментами написание однотипного кода — рутина: создание компонентов, настройка навигации, обработка API.
Здесь на помощь приходят промты — готовые текстовые заготовки для AI-ассистентов (ChatGPT, Claude, Copilot). Я собрал 10 проверенных промтов, которые использую каждый день в реальных проектах. Они сэкономят часы работы и помогут избежать типичных ошибок. Каждый промт сопровождается примером кода и пояснением.
1. Быстрое создание функционального компонента с TypeScript
Промт:
Напиши функциональный компонент React Native на TypeScript с пропсами
title: string,onPress: () => void,variant: 'primary' | 'secondary'. Компонент должен быть кнопкой с анимацией нажатия (Opacity) и поддержкой кастомных стилей черезstyleпропс. ИспользуйReact.memoдля оптимизации.
Пример результата:
import React, { memo } from 'react';
import { TouchableOpacity, Text, StyleSheet, ViewStyle } from 'react-native';
interface ButtonProps {
title: string;
onPress: () => void;
variant?: 'primary' | 'secondary';
style?: ViewStyle;
}
const AppButton: React.FC<ButtonProps> = memo(({ title, onPress, variant = 'primary', style }) => {
return (
<TouchableOpacity
onPress={onPress}
activeOpacity={0.7}
style={[
styles.base,
variant === 'primary' ? styles.primary : styles.secondary,
style,
]}
>
<Text style={variant === 'primary' ? styles.primaryText : styles.secondaryText}>
{title}
</Text>
</TouchableOpacity>
);
});
const styles = StyleSheet.create({
base: { paddingVertical: 12, paddingHorizontal: 24, borderRadius: 8, alignItems: 'center' },
primary: { backgroundColor: '#007AFF' },
secondary: { backgroundColor: 'transparent', borderWidth: 1, borderColor: '#007AFF' },
primaryText: { color: '#FFFFFF', fontSize: 16, fontWeight: '600' },
secondaryText: { color: '#007AFF', fontSize: 16 },
});
export default AppButton;
Почему это работает: Промт явно указывает тип пропсов, стиль анимации и React.memo. Это снижает количество перерисовок — критично для списков.
2. Экран со списком из FlatList и pull-to-refresh
Промт:
Создай экран React Native с FlatList, который загружает данные из
https://jsonplaceholder.typicode.com/posts. Добавь pull-to-refresh, индикатор загрузки при первом рендере, обработку ошибок (покажи Alert при неудаче). Тип данных:{ id: number, title: string, body: string }. ИспользуйuseEffectиuseState.
Пример результата:
import React, { useState, useEffect } from 'react';
import { FlatList, Text, View, ActivityIndicator, Alert, RefreshControl } from 'react-native';
interface Post {
id: number;
title: string;
body: string;
}
const PostsScreen: React.FC = () => {
const [posts, setPosts] = useState<Post[]>([]);
const [loading, setLoading] = useState(true);
const [refreshing, setRefreshing] = useState(false);
const fetchPosts = async (isRefresh = false) => {
try {
const response = await fetch('https://jsonplaceholder.typicode.com/posts');
if (!response.ok) throw new Error('Network error');
const data: Post[] = await response.json();
setPosts(data);
} catch (error) {
Alert.alert('Ошибка', 'Не удалось загрузить посты');
} finally {
setLoading(false);
if (isRefresh) setRefreshing(false);
}
};
useEffect(() => { fetchPosts(); }, []);
const onRefresh = () => {
setRefreshing(true);
fetchPosts(true);
};
if (loading) return <ActivityIndicator size="large" style={{ flex: 1 }} />;
return (
<FlatList
data={posts}
keyExtractor={(item) => item.id.toString()}
renderItem={({ item }) => (
<View style={{ padding: 16, borderBottomWidth: 1, borderColor: '#ccc' }}>
<Text style={{ fontSize: 18, fontWeight: 'bold' }}>{item.title}</Text>
<Text>{item.body}</Text>
</View>
)}
refreshControl={<RefreshControl refreshing={refreshing} onRefresh={onRefresh} />}
/>
);
};
export default PostsScreen;
Совет: Замени URL на реальный API вашего бэкенда. AST Biont поддерживает подключение к JSON API через настраиваемые эндпоинты — подробнее на asibiont.com/courses.
3. Настройка навигации с React Navigation (Stack + Tabs)
Промт:
Настрой React Navigation v7 в приложении: нижние табы (Home, Profile) и внутри каждого таба — стек (HomeScreen -> DetailsScreen, ProfileScreen -> SettingsScreen). Используй
@react-navigation/native,@react-navigation/bottom-tabs,@react-navigation/native-stack. Покажи минимальный код для App.tsx.
Пример результата:
import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
const Tab = createBottomTabNavigator();
const HomeStack = createNativeStackNavigator();
const ProfileStack = createNativeStackNavigator();
function HomeStackScreen() {
return (
<HomeStack.Navigator>
<HomeStack.Screen name="Home" component={HomeScreen} />
<HomeStack.Screen name="Details" component={DetailsScreen} />
</HomeStack.Navigator>
);
}
function ProfileStackScreen() {
return (
<ProfileStack.Navigator>
<ProfileStack.Screen name="Profile" component={ProfileScreen} />
<ProfileStack.Screen name="Settings" component={SettingsScreen} />
</ProfileStack.Navigator>
);
}
export default function App() {
return (
<NavigationContainer>
<Tab.Navigator>
<Tab.Screen name="HomeTab" component={HomeStackScreen} options={{ title: 'Главная' }} />
<Tab.Screen name="ProfileTab" component={ProfileStackScreen} options={{ title: 'Профиль' }} />
</Tab.Navigator>
</NavigationContainer>
);
}
Важно: Начиная с React Navigation 6, всё строится через Navigator и Screen. Промт сразу задаёт структуру, что экономит время на чтении документации.
4. Кастомный хук для работы с API (useFetch)
Промт:
Напиши кастомный хук
useFetch<T>на TypeScript для React Native. Он должен принимать URL, опциональные параметры запроса (method, headers, body). Возвращать: `data: T
| null,loading: boolean,error: string | null. Добавь автоматическую отмену запроса при размонтировании компонента черезAbortController`.
Пример результата:
import { useState, useEffect, useRef } from 'react';
interface FetchOptions {
method?: 'GET'
| 'POST' | 'PUT' | 'DELETE';
headers?: Record<string, string>;
body?: unknown;
}
function useFetch<T>(url: string, options?: FetchOptions) {
const [data, setData] = useState<T | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
const abortRef = useRef<AbortController | null>(null);
useEffect(() => {
abortRef.current = new AbortController();
const fetchData = async () => {
try {
const response = await fetch(url, {
...options,
signal: abortRef.current!.signal,
headers: { 'Content-Type': 'application/json', ...options?.headers },
body: options?.body ? JSON.stringify(options.body) : undefined,
});
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const result: T = await response.json();
setData(result);
} catch (err) {
if (err instanceof Error && err.name !== 'AbortError') {
setError(err.message);
}
} finally {
setLoading(false);
}
};
fetchData();
return () => abortRef.current?.abort();
}, [url]);
return { data, loading, error };
}
export default useFetch;
Зачем: Хук предотвращает утечки памяти (известная проблема React Native) и унифицирует логику запросов.
5. Анимированная загрузка с Lottie
Промт:
Напиши компонент
LottieLoader, который принимает пропсvisible: boolean. Покаvisible— показывает анимацию Lottie из файлаanimation.json(путь../assets/animation.json) на полупрозрачном фоне. Используй библиотекуlottie-react-native. Добавь кнопку «Закрыть» для тестирования.
Пример результата:
import React from 'react';
import { Modal, View, TouchableOpacity, Text, StyleSheet } from 'react-native';
import LottieView from 'lottie-react-native';
interface LottieLoaderProps {
visible: boolean;
onClose?: () => void;
}
const LottieLoader: React.FC<LottieLoaderProps> = ({ visible, onClose }) => {
return (
<Modal transparent visible={visible} animationType="fade">
<View style={styles.overlay}>
<LottieView
source={require('../assets/animation.json')}
autoPlay
loop
style={{ width: 200, height: 200 }}
/>
{onClose && (
<TouchableOpacity onPress={onClose} style={styles.closeButton}>
<Text style={styles.closeText}>Закрыть</Text>
</TouchableOpacity>
)}
</View>
</Modal>
);
};
const styles = StyleSheet.create({
overlay: {
flex: 1,
backgroundColor: 'rgba(0,0,0,0.5)',
justifyContent: 'center',
alignItems: 'center',
},
closeButton: { marginTop: 20, padding: 10, backgroundColor: '#fff', borderRadius: 8 },
closeText: { color: '#007AFF' },
});
export default LottieLoader;
Нюанс: Lottie-файлы (JSON-анимации) можно найти на LottieFiles. Промт сразу включает Modal для корректного наложения на экран.
6. Форма с валидацией (React Hook Form + Zod)
Промт:
Создай экран регистрации с полями: email, password (мин. 8 символов), confirmPassword (должен совпадать с password). Используй React Hook Form v7 и Zod для схемы валидации. Покажи ошибки под каждым полем. Кнопка отправки выводит данные в консоль.
Пример результата:
import React from 'react';
import { View, TextInput, Button, Text, StyleSheet } from 'react-native';
import { useForm, Controller } from 'react-hook-form';
import { z } from 'zod';
import { zodResolver } from '@hookform/resolvers/zod';
const schema = z.object({
email: z.string().email('Некорректный email'),
password: z.string().min(8, 'Минимум 8 символов'),
confirmPassword: z.string(),
}).refine((data) => data.password === data.confirmPassword, {
message: 'Пароли не совпадают',
path: ['confirmPassword'],
});
type FormData = z.infer<typeof schema>;
const RegisterScreen: React.FC = () => {
const { control, handleSubmit, formState: { errors } } = useForm<FormData>({
resolver: zodResolver(schema),
});
const onSubmit = (data: FormData) => console.log(data);
return (
<View style={styles.container}>
<Controller
control={control}
name="email"
render={({ field: { onChange, value } }) => (
<TextInput placeholder="Email" onChangeText={onChange} value={value} style={styles.input} />
)}
/>
{errors.email && <Text style={styles.error}>{errors.email.message}</Text>}
<Controller
control={control}
name="password"
render={({ field: { onChange, value } }) => (
<TextInput placeholder="Password" secureTextEntry onChangeText={onChange} value={value} style={styles.input} />
)}
/>
{errors.password && <Text style={styles.error}>{errors.password.message}</Text>}
<Controller
control={control}
name="confirmPassword"
render={({ field: { onChange, value } }) => (
<TextInput placeholder="Confirm Password" secureTextEntry onChangeText={onChange} value={value} style={styles.input} />
)}
/>
{errors.confirmPassword && <Text style={styles.error}>{errors.confirmPassword.message}</Text>}
<Button title="Зарегистрироваться" onPress={handleSubmit(onSubmit)} />
</View>
);
};
const styles = StyleSheet.create({
container: { padding: 20 },
input: { borderWidth: 1, borderColor: '#ccc', padding: 10, marginVertical: 8, borderRadius: 6 },
error: { color: 'red', fontSize: 12, marginBottom: 8 },
});
export default RegisterScreen;
Преимущество: Zod даёт строгую типизацию, а React Hook Form минимизирует перерисовки.
7. Оптимизация FlatList с getItemLayout и ключами
Промт:
Напиши компонент
OptimizedList, который отображает 1000 элементов (каждый — строка с номером). ИспользуйgetItemLayoutдля фиксированной высоты (50px),keyExtractorна основе индекса,initialNumToRender={10}иmaxToRenderPerBatch={5}. Докажи, что это снижает лаги.
Пример результата:
import React from 'react';
import { FlatList, Text, View } from 'react-native';
const data = Array.from({ length: 1000 }, (_, i) => ({ id: i, title: `Item ${i + 1}` }));
const OptimizedList: React.FC = () => {
return (
<FlatList
data={data}
keyExtractor={(item) => item.id.toString()}
renderItem={({ item }) => (
<View style={{ height: 50, justifyContent: 'center', paddingHorizontal: 16, borderBottomWidth: 1 }}>
<Text>{item.title}</Text>
</View>
)}
getItemLayout={(_, index) => ({ length: 50, offset: 50 * index, index })}
initialNumToRender={10}
maxToRenderPerBatch={5}
windowSize={5}
/>
);
};
export default OptimizedList;
Почему это важно: FlatList без getItemLayout вычисляет позиции динамически — на 1000 элементах это вызывает заметные лаги. Фиксированная высота решает проблему.
8. Обработка ошибок с ErrorBoundary
Промт:
Напиши классовый компонент
ErrorBoundaryдля React Native. Лови ошибки дочерних компонентов, показывай экран с текстом «Что-то пошло не так» и кнопкой «Попробовать снова» (сбрасывает состояние). ИспользуйcomponentDidCatchиgetDerivedStateFromError.
Пример результата:
import React, { Component, ErrorInfo, ReactNode } from 'react';
import { View, Text, TouchableOpacity, StyleSheet } from 'react-native';
interface Props { children: ReactNode; }
interface State { hasError: boolean; }
class ErrorBoundary extends Component<Props, State> {
constructor(props: Props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(): State { return { hasError: true }; }
componentDidCatch(error: Error, errorInfo: ErrorInfo) {
console.error('Ошибка:', error, errorInfo);
}
resetError = () => this.setState({ hasError: false });
render() {
if (this.state.hasError) {
return (
<View style={styles.container}>
<Text style={styles.title}>Что-то пошло не так</Text>
<TouchableOpacity onPress={this.resetError} style={styles.button}>
<Text style={styles.buttonText}>Попробовать снова</Text>
</TouchableOpacity>
</View>
);
}
return this.props.children;
}
}
const styles = StyleSheet.create({
container: { flex: 1, justifyContent: 'center', alignItems: 'center', padding: 20 },
title: { fontSize: 18, marginBottom: 20, color: '#333' },
button: { backgroundColor: '#007AFF', padding: 12, borderRadius: 8 },
buttonText: { color: '#fff', fontSize: 16 },
});
export default ErrorBoundary;
Примечание: Классовый компонент обязателен для ErrorBoundary — хуки не работают с componentDidCatch.
9. Интеграция камеры (react-native-vision-camera)
Промт:
Напиши экран с камерой, используя
react-native-vision-camera(версия 4+). Запроси разрешение на камеру черезuseCameraPermission, покажи превью, добавь кнопку съёмки (сохраняет фото в временную директорию). Покажи сообщение, если разрешение не дано.
Пример результата:
import React, { useRef } from 'react';
import { View, TouchableOpacity, Text, StyleSheet, Alert } from 'react-native';
import { Camera, useCameraDevice, useCameraPermission } from 'react-native-vision-camera';
const CameraScreen: React.FC = () => {
const device = useCameraDevice('back');
const { hasPermission, requestPermission } = useCameraPermission();
const cameraRef = useRef<Camera>(null);
if (!hasPermission) {
return (
<View style={styles.container}>
<Text>Нет разрешения на камеру</Text>
<TouchableOpacity onPress={requestPermission} style={styles.button}>
<Text>Разрешить доступ</Text>
</TouchableOpacity>
</View>
);
}
if (!device) return <Text>Камера не найдена</Text>;
const takePhoto = async () => {
try {
const photo = await cameraRef.current?.takePhoto();
Alert.alert('Фото сохранено', `Путь: ${photo?.path}`);
} catch (err) {
Alert.alert('Ошибка', 'Не удалось сделать фото');
}
};
return (
<View style={styles.container}>
<Camera
ref={cameraRef}
style={StyleSheet.absoluteFill}
device={device}
isActive={true}
photo={true}
/>
<TouchableOpacity onPress={takePhoto} style={styles.captureButton}>
<View style={styles.captureInner} />
</TouchableOpacity>
</View>
);
};
const styles = StyleSheet.create({
container: { flex: 1 },
button: { marginTop: 20, padding: 10, backgroundColor: '#007AFF', borderRadius: 8 },
captureButton: { position: 'absolute', bottom: 50, alignSelf: 'center', width: 70, height: 70, borderRadius: 35, backgroundColor: '#fff', justifyContent: 'center', alignItems: 'center' },
captureInner: { width: 60, height: 60, borderRadius: 30, backgroundColor: '#fff', borderWidth: 2, borderColor: '#000' },
});
export default CameraScreen;
Важно: Vision Camera 4+ требует iOS 13+ и Android 10+. Проверьте Info.plist и AndroidManifest.xml.
10. Работа с хранилищем (AsyncStorage + MMKV)
Промт:
Напиши сервис
StorageServiceна TypeScript, который используетreact-native-mmkv(основное хранилище) и@react-native-async-storage/async-storageкак fallback. Методы:getString(key),setString(key, value),getObject<T>,setObject,delete,clearAll. Обработай ошибки.
Пример результата:
import { MMKV } from 'react-native-mmkv';
import AsyncStorage from '@react-native-async-storage/async-storage';
const mmkv = new MMKV();
class StorageService {
private useMMKV = true;
getString(key: string): string | null {
try {
return this.useMMKV ? mmkv.getString(key) ?? null : AsyncStorage.getItem(key);
} catch {
return null;
}
}
setString(key: string, value: string): void {
try {
this.useMMKV ? mmkv.set(key, value) : AsyncStorage.setItem(key, value);
} catch (err) {
console.error('Storage set error:', err);
}
}
getObject<T>(key: string): T | null {
const value = this.getString(key);
return value ? JSON.parse(value) : null;
}
setObject(key: string, value: unknown): void {
this.setString(key, JSON.stringify(value));
}
delete(key: string): void {
try {
this.useMMKV ? mmkv.delete(key) : AsyncStorage.removeItem(key);
} catch (err) {
console.error('Storage delete error:', err);
}
}
clearAll(): void {
try {
this.useMMKV ? mmkv.clearAll() : AsyncStorage.clear();
} catch (err) {
console.error('Storage clear error:', err);
}
}
}
export const storage = new StorageService();
Зачем MMKV: AsyncStorage — асинхронный, что замедляет холодный старт. MMKV — синхронный и в 30 раз быстрее (данные из бенчмарков библиотеки).
Заключение
Эти 10 промтов покрывают 80% повседневных задач в React Native: от UI-компонентов до работы с навигацией и API. Главный совет — адаптируйте промты под свой стек и версии библиотек. Например, React Navigation v7 уже использует @react-navigation/native-stack вместо @react-navigation/stack; Lottie обновила API в 2025 году. Регулярно проверяйте документацию — в 2026 году вышла версия React Native 0.77 с улучшенной производительностью.
Для углублённого изучения рекомендую:
- Официальную документацию React Native (reactnative.dev)
- Репозиторий React Navigation (reactnavigation.org)
- Блог Expo (expo.dev/blog) — если используете Expo.
Пишите свои промты в комментариях — поделюсь ещё 5 штуками из личного набора.
Комментарии