10 Prompts for React Native: UI Components, Navigation, and API Handling

Introduction

React Native has become a go-to framework for building cross-platform mobile apps. Whether you're designing reusable UI components, implementing complex navigation flows, or integrating REST APIs, writing efficient code can be time-consuming. AI prompts can accelerate your workflow by generating boilerplate, suggesting best practices, and debugging common issues. This guide presents 10 carefully crafted prompts—covering UI, navigation, and API work—that will help you build faster with React Native.

1. Generate a Custom Button Component

Prompt: "Create a reusable CustomButton component in React Native with props for title, onPress, variant (primary/secondary/outline), and disabled. Include TypeScript types and style the component using StyleSheet. Add a loading spinner when isLoading is true."

Why it helps: This prompt produces a production-ready button that fits into any design system. It enforces type safety and covers loading states.

import React from 'react';
import { TouchableOpacity, Text, ActivityIndicator, StyleSheet } from 'react-native';

type ButtonVariant = 'primary'

| 'secondary' | 'outline';

interface CustomButtonProps {
  title: string;
  onPress: () => void;
  variant?: ButtonVariant;
  disabled?: boolean;
  isLoading?: boolean;
}

const CustomButton: React.FC<CustomButtonProps> = ({
  title,
  onPress,
  variant = 'primary',
  disabled = false,
  isLoading = false,
}) => {
  const isDisabled = disabled || isLoading;
  return (
    <TouchableOpacity
      style={[styles.button, styles[variant], isDisabled && styles.disabled]}
      onPress={onPress}
      disabled={isDisabled}
      activeOpacity={0.7}
    >
      {isLoading ? (
        <ActivityIndicator color="#fff" />
      ) : (
        <Text style={styles.text}>{title}</Text>
      )}
    </TouchableOpacity>
  );
};

export default CustomButton;

const styles = StyleSheet.create({
  button: { paddingVertical: 12, paddingHorizontal: 24, borderRadius: 8, alignItems: 'center' },
  primary: { backgroundColor: '#007BFF' },
  secondary: { backgroundColor: '#6C757D' },
  outline: { backgroundColor: 'transparent', borderWidth: 1, borderColor: '#007BFF' },
  disabled: { opacity: 0.5 },
  text: { color: '#fff', fontSize: 16, fontWeight: '600' },
});

2. Create a FlatList with Pull-to-Refresh and Infinite Scroll

Prompt: "Write a React Native FlatList component that fetches paginated data from an API endpoint. Implement pull-to-refresh and infinite scroll (load more when reaching the end). Use useState and useEffect. Handle loading, error, and empty states."

Why it helps: Lists are core to mobile apps. This prompt generates a robust pattern for data-fetching lists, saving you from reinventing the wheel.

import React, { useState, useEffect, useCallback } from 'react';
import { FlatList, View, Text, ActivityIndicator, StyleSheet } from 'react-native';

const PAGE_SIZE = 20;

const DataList: React.FC = () => {
  const [data, setData] = useState<any[]>([]);
  const [page, setPage] = useState(1);
  const [loading, setLoading] = useState(false);
  const [refreshing, setRefreshing] = useState(false);
  const [hasMore, setHasMore] = useState(true);

  const fetchData = async (pageNum: number, isRefresh = false) => {
    setLoading(true);
    try {
      const response = await fetch(`https://api.example.com/items?page=${pageNum}&limit=${PAGE_SIZE}`);
      const result = await response.json();
      if (isRefresh) {
        setData(result.items);
      } else {
        setData(prev => [...prev, ...result.items]);
      }
      setHasMore(result.items.length === PAGE_SIZE);
    } catch (error) {
      console.error(error);
    } finally {
      setLoading(false);
    }
  };

  useEffect(() => { fetchData(1, true); }, []);

  const onRefresh = useCallback(async () => {
    setRefreshing(true);
    setPage(1);
    await fetchData(1, true);
    setRefreshing(false);
  }, []);

  const loadMore = () => {
    if (!loading && hasMore) {
      const nextPage = page + 1;
      setPage(nextPage);
      fetchData(nextPage);
    }
  };

  const renderFooter = () => (loading ? <ActivityIndicator style={{ padding: 10 }} /> : null);

  return (
    <FlatList
      data={data}
      keyExtractor={(item) => item.id.toString()}
      renderItem={({ item }) => <View><Text>{item.name}</Text></View>}
      onRefresh={onRefresh}
      refreshing={refreshing}
      onEndReached={loadMore}
      onEndReachedThreshold={0.5}
      ListFooterComponent={renderFooter}
      ListEmptyComponent={!loading && <Text>No data</Text>}
    />
  );
};

export default DataList;

3. Implement React Navigation Stack with TypeScript

Prompt: "Set up a React Navigation stack navigator in a React Native TypeScript project. Include two screens: HomeScreen and DetailsScreen. Pass a productId parameter from Home to Details. Create a typed RootStackParamList."

Why it helps: Type-safe navigation prevents runtime errors and improves developer experience. This prompt gives you the boilerplate.

// navigation/types.ts
export type RootStackParamList = {
  Home: undefined;
  Details: { productId: number };
};

// App.tsx
import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import HomeScreen from './screens/HomeScreen';
import DetailsScreen from './screens/DetailsScreen';

const Stack = createNativeStackNavigator<RootStackParamList>();

export default function App() {
  return (
    <NavigationContainer>
      <Stack.Navigator initialRouteName="Home">
        <Stack.Screen name="Home" component={HomeScreen} />
        <Stack.Screen name="Details" component={DetailsScreen} />
      </Stack.Navigator>
    </NavigationContainer>
  );
}

4. Build a Tab Navigator with Badge Icons

Prompt: "Create a bottom tab navigator with three tabs: Home, Search, and Profile. Each tab should use React Native vector icons. Add a badge count (e.g., unread notifications) on the Home tab. Use @react-navigation/bottom-tabs."

Why it helps: Tab navigation is standard in mobile apps. This prompt shows how to customise tab bars with badges.

import React from 'react';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import Icon from 'react-native-vector-icons/Ionicons';
import HomeScreen from './screens/HomeScreen';
import SearchScreen from './screens/SearchScreen';
import ProfileScreen from './screens/ProfileScreen';

const Tab = createBottomTabNavigator();

export default function TabNavigator() {
  return (
    <Tab.Navigator
      screenOptions={({ route }) => ({
        tabBarIcon: ({ focused, color, size }) => {
          let iconName: string;
          if (route.name === 'Home') iconName = focused ? 'home' : 'home-outline';
          else if (route.name === 'Search') iconName = focused ? 'search' : 'search-outline';
          else iconName = focused ? 'person' : 'person-outline';
          return <Icon name={iconName} size={size} color={color} />;
        },
        tabBarActiveTintColor: 'tomato',
        tabBarInactiveTintColor: 'gray',
      })}
    >
      <Tab.Screen
        name="Home"
        component={HomeScreen}
        options={{ tabBarBadge: 3 }}
      />
      <Tab.Screen name="Search" component={SearchScreen} />
      <Tab.Screen name="Profile" component={ProfileScreen} />
    </Tab.Navigator>
  );
}

5. Fetch Data with Axios and Manage Loading/Error States

Prompt: "Write a custom hook useApi in React Native that takes a URL string, returns { data, loading, error }, and uses Axios. Include a refetch function. Handle network errors gracefully."

Why it helps: Centralising API calls into a hook reduces code duplication and improves error handling.

import { useState, useEffect, useCallback } from 'react';
import axios, { AxiosResponse } from 'axios';

interface UseApiResult<T> {
  data: T | null;
  loading: boolean;
  error: string | null;
  refetch: () => void;
}

function useApi<T>(url: string): UseApiResult<T> {
  const [data, setData] = useState<T | null>(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);

  const fetchData = useCallback(async () => {
    setLoading(true);
    setError(null);
    try {
      const response: AxiosResponse<T> = await axios.get(url);
      setData(response.data);
    } catch (err: any) {
      setError(err.message || 'Something went wrong');
    } finally {
      setLoading(false);
    }
  }, [url]);

  useEffect(() => { fetchData(); }, [fetchData]);

  return { data, loading, error, refetch: fetchData };
}

export default useApi;

6. Create a Modal with Custom Animation

Prompt: "Build a reusable Modal component in React Native that slides up from the bottom. Use Animated API. Accept visible, onClose, and children props. Add a semi-transparent backdrop."

Why it helps: Modals are common for confirmations, forms, and settings. Animated modals improve UX.

import React, { useEffect, useRef } from 'react';
import { Animated, TouchableWithoutFeedback, View, StyleSheet, Dimensions } from 'react-native';

const { height: SCREEN_HEIGHT } = Dimensions.get('window');

interface BottomModalProps {
  visible: boolean;
  onClose: () => void;
  children: React.ReactNode;
}

const BottomModal: React.FC<BottomModalProps> = ({ visible, onClose, children }) => {
  const translateY = useRef(new Animated.Value(SCREEN_HEIGHT)).current;

  useEffect(() => {
    Animated.timing(translateY, {
      toValue: visible ? 0 : SCREEN_HEIGHT,
      duration: 300,
      useNativeDriver: true,
    }).start();
  }, [visible]);

  if (!visible) return null;

  return (
    <View style={styles.overlay}>
      <TouchableWithoutFeedback onPress={onClose}>
        <View style={styles.backdrop} />
      </TouchableWithoutFeedback>
      <Animated.View style={[styles.container, { transform: [{ translateY }] }]}>
        {children}
      </Animated.View>
    </View>
  );
};

export default BottomModal;

const styles = StyleSheet.create({
  overlay: { position: 'absolute', top: 0, left: 0, right: 0, bottom: 0, justifyContent: 'flex-end' },
  backdrop: { ...StyleSheet.absoluteFillObject, backgroundColor: 'rgba(0,0,0,0.5)' },
  container: { backgroundColor: 'white', borderTopLeftRadius: 20, borderTopRightRadius: 20, padding: 20 },
});

7. Handle Form Input with Validation

Prompt: "Create a form with email and password fields in React Native. Validate email format and password length (min 8 characters). Show error messages below each field. Use TextInput and TouchableOpacity. Disable the submit button if validation fails."

Why it helps: Forms are essential; this prompt gives a clean pattern for validation and error display.

import React, { useState } from 'react';
import { View, TextInput, Text, TouchableOpacity, StyleSheet } from 'react-native';

const LoginForm: React.FC = () => {
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const [errors, setErrors] = useState({ email: '', password: '' });

  const validate = (): boolean => {
    const newErrors = { email: '', password: '' };
    if (!/\S+@\S+\.\S+/.test(email)) newErrors.email = 'Invalid email';
    if (password.length < 8) newErrors.password = 'Password must be at least 8 characters';
    setErrors(newErrors);
    return !newErrors.email && !newErrors.password;
  };

  const handleSubmit = () => {
    if (validate()) {
      // submit logic
    }
  };

  return (
    <View style={styles.container}>
      <TextInput style={styles.input} placeholder="Email" value={email} onChangeText={setEmail} keyboardType="email-address" />
      {errors.email ? <Text style={styles.error}>{errors.email}</Text> : null}
      <TextInput style={styles.input} placeholder="Password" value={password} onChangeText={setPassword} secureTextEntry />
      {errors.password ? <Text style={styles.error}>{errors.password}</Text> : null}
<TouchableOpacity style={[styles.button, (email === ''

|| password === '') && styles.disabled]} onPress={handleSubmit} disabled={email === '' || password === ''}>
        <Text style={styles.buttonText}>Submit</Text>
      </TouchableOpacity>
    </View>
  );
};

export default LoginForm;

const styles = StyleSheet.create({
  container: { padding: 20 },
  input: { borderWidth: 1, borderColor: '#ccc', borderRadius: 8, padding: 10, marginBottom: 10 },
  error: { color: 'red', marginBottom: 10 },
  button: { backgroundColor: '#007BFF', padding: 12, borderRadius: 8, alignItems: 'center' },
  buttonText: { color: '#fff', fontSize: 16 },
  disabled: { opacity: 0.5 },
});

8. Style Components Using a Theme Object

Prompt: "Design a theme object for a React Native app that includes colors, fonts, spacing, and shadows. Show how to use it with StyleSheet.create and useTheme hook (or context). Example: a Card component that uses theme values."

Why it helps: Theming ensures consistency across screens and simplifies dark mode support.

// theme.ts
export const theme = {
  colors: {
    primary: '#6200EE',
    background: '#FFFFFF',
    surface: '#F5F5F5',
    text: '#000000',
    error: '#B00020',
  },
  fonts: {
    regular: 16,
    medium: 18,
    large: 24,
  },
  spacing: {
    small: 8,
    medium: 16,
    large: 24,
  },
  shadows: {
    elevation: 2,
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 2 },
    shadowOpacity: 0.1,
    shadowRadius: 4,
  },
};

// Card.tsx
import React from 'react';
import { View, Text, StyleSheet } from 'react-native';
import { theme } from './theme';

interface CardProps {
  title: string;
  description: string;
}

const Card: React.FC<CardProps> = ({ title, description }) => (
  <View style={styles.card}>
    <Text style={styles.title}>{title}</Text>
    <Text style={styles.description}>{description}</Text>
  </View>
);

const styles = StyleSheet.create({
  card: {
    backgroundColor: theme.colors.surface,
    padding: theme.spacing.medium,
    borderRadius: 8,
    ...theme.shadows,
  },
  title: { fontSize: theme.fonts.medium, color: theme.colors.text, marginBottom: theme.spacing.small },
  description: { fontSize: theme.fonts.regular, color: theme.colors.text },
});

9. Add Push Notifications with Firebase Cloud Messaging

Prompt: "Integrate push notifications in a React Native app using @react-native-firebase/messaging. Write code to request permission, get the FCM token, and display a local notification when the app is in foreground. Handle notification tap to navigate to a specific screen."

Why it helps: Push notifications boost user engagement. This prompt gives a practical setup with Firebase.

import messaging from '@react-native-firebase/messaging';
import { Platform } from 'react-native';
import notifee, { AndroidImportance } from '@notifee/react-native';

async function requestPermission(): Promise<string | null> {
  const authStatus = await messaging().requestPermission();
  const enabled = authStatus === messaging.AuthorizationStatus.AUTHORIZED || authStatus === messaging.AuthorizationStatus.PROVISIONAL;
  if (enabled) {
    return await messaging().getToken();
  }
  return null;
}

async function displayNotification(remoteMessage: any) {
  const channelId = await notifee.createChannel({
    id: 'default',
    name: 'Default Channel',
    importance: AndroidImportance.HIGH,
  });
  await notifee.displayNotification({
    title: remoteMessage.notification?.title,
    body: remoteMessage.notification?.body,
    android: { channelId },
  });
}

// In App.tsx
useEffect(() => {
  const unsubscribe = messaging().onMessage(async remoteMessage => {
    displayNotification(remoteMessage);
  });
  return unsubscribe;
}, []);

10. Optimize Performance with useMemo and useCallback

Prompt: "Write a React Native component that renders a large FlatList. Use useMemo to memoize a filtered data array and useCallback for the renderItem function. Explain how these hooks prevent unnecessary re-renders."

Why it helps: Performance is critical in mobile apps. This prompt teaches optimisation patterns.

import React, { useMemo, useCallback, useState } from 'react';
import { FlatList, View, Text, TextInput, StyleSheet } from 'react-native';

interface Item { id: number; name: string; }

const ListWithFilter: React.FC<{ items: Item[] }> = ({ items }) => {
  const [filter, setFilter] = useState('');

  const filteredItems = useMemo(() => {
    return items.filter(item => item.name.toLowerCase().includes(filter.toLowerCase()));
  }, [items, filter]);

  const renderItem = useCallback(({ item }: { item: Item }) => (
    <View style={styles.item}>
      <Text>{item.name}</Text>
    </View>
  ), []);

  return (
    <View>
      <TextInput placeholder="Search" value={filter} onChangeText={setFilter} style={styles.input} />
      <FlatList
        data={filteredItems}
        keyExtractor={item => item.id.toString()}
        renderItem={renderItem}
      />
    </View>
  );
};

const styles = StyleSheet.create({
  input: { borderWidth: 1, borderColor: '#ccc', padding: 10, margin: 10 },
  item: { padding: 10, borderBottomWidth: 1, borderBottomColor: '#eee' },
});

Conclusion

These 10 prompts cover the most common React Native tasks—from UI components and navigation to data fetching and performance. By using them as starting points, you can reduce boilerplate and focus on your app’s unique logic. Each prompt is designed to be adaptable; feel free to tweak the code to match your project’s specific requirements. Try one out in your next build and see how much time you save.

← All posts

Comments