10 промтов для React Native: компоненты, навигация, API — ускорь мобильную разработку

Введение

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 штуками из личного набора.

← Все статьи

Комментарии

Читайте также

Дженсен Хуанг возглавил рейтинг лучших CEO 2026 года по версии Glassdoor: секреты успеха NVIDIA и «vibe coding»

14 августа 2026

One Inline Button для всех: параметры, аутентификация и колбэки в Telegram Mini App

14 августа 2026

RustDesk теперь поддерживает настоящий неограниченный удалённый доступ на Wayland: что это значит для разработчиков и сисадминов

14 августа 2026

Интеграция LiDAR (RPLIDAR, TFmini) с AI-агентом ASI Biont: навигация роботов и автоматизация сканирования

14 августа 2026

Telegram (каналы, группы) и ИИ-агент: автоматизируйте управление сообществом с помощью ASI Biont

14 августа 2026

Cambridge International A-Level Economics (9708): обзор курса и подготовка на asibiont.com

14 августа 2026

Интеграция SAP Business One с ИИ-агентом: 5 сценариев автоматизации для снижения затрат на ERP на 75% в 2026 году

14 августа 2026

Cambridge Alevel English Language (9093): полный обзор курса и обучение на asibiont.com

14 августа 2026

ERP и SAP в 2026 году: тенденции интеграции и как наш курс SAP S/4HANA готовит вас к предприятию, управляемому искусственным интеллектом

14 августа 2026