100 React Native practice problems with solutions

Staring at React Native code feels comfortable. Watching tutorials makes sense. But when it’s time to build your own app, suddenly everything goes blank – and that feeling can be really discouraging. You’re not alone, and this post exists to turn that blank moment into a breakthrough.

Here are 100 React Native practice problems with clear, step-by-step solutions that take you from understanding code to writing it with genuine confidence. You’ll start with simple components, JSX, and styling, then master state management, navigation, FlatLists, API calls, hooks, and even basic animations. Each problem is written in plain, everyday language. You try the challenge yourself first, then check the solution and truly learn the why behind every line.

Why is deliberate practice so powerful? Because app development is a hands-on skill. Every problem you solve builds muscle memory, sharpens your debugging instinct, and transforms scattered knowledge into the ability to launch real apps from scratch. That’s what makes you valuable – not just someone who “knows React Native,” but someone who can build, problem-solve, and deliver.

Whether you’re falling in love with mobile development or preparing for a front-end interview, these exercises will make you feel prepared, capable, and excited. Pick a problem, open your editor, and experience that amazing “I’m really building this!” moment today.

Also try it: 100 Java practice problems with solutions

1. Create a React Native component that displays “Hello, World!” on the screen.

jsx

import React from 'react';
import { Text, View } from 'react-native';
const App = () => (
  <View><Text>Hello, World!</Text></View>
);
export default App;

2. Use the useState hook to create a counter that increments when a button is pressed.

jsx

import React, { useState } from 'react';
import { View, Text, Button } from 'react-native';
const Counter = () => {
  const [count, setCount] = useState(0);
  return (
    <View>
      <Text>{count}</Text>
      <Button title="Increment" onPress={() => setCount(count + 1)} />
    </View>
  );
};
export default Counter;

3. Display a list of items using FlatList with hardcoded data.

jsx

import React from 'react';
import { FlatList, Text, View } from 'react-native';
const data = [{ id: '1', name: 'Apple' }, { id: '2', name: 'Banana' }];
const ListExample = () => (
  <FlatList data={data} renderItem={({ item }) => <Text>{item.name}</Text>} keyExtractor={item => item.id} />
);
export default ListExample;

4. Create a functional component that accepts props (name) and displays a greeting.

jsx

import React from 'react';
import { Text } from 'react-native';
const Greeting = ({ name }) => <Text>Hello, {name}!</Text>;
export default Greeting;

5. Use TextInput to capture user input and display it below.

jsx

import React, { useState } from 'react';
import { TextInput, Text, View } from 'react-native';
const InputDisplay = () => {
  const [text, setText] = useState('');
  return (
    <View>
      <TextInput placeholder="Type here" onChangeText={setText} />
      <Text>You typed: {text}</Text>
    </View>
  );
};
export default InputDisplay;

6. Apply a custom style using StyleSheet to center text and set background color.

jsx

import React from 'react';
import { View, Text, StyleSheet } from 'react-native';
const StyledBox = () => (
  <View style={styles.container}>
    <Text style={styles.text}>Centered text</Text>
  </View>
);
const styles = StyleSheet.create({
  container: { flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: 'lightblue' },
  text: { fontSize: 20, color: 'darkblue' }
});
export default StyledBox;

7. Use TouchableOpacity to change background color on press (simulate).

jsx

import React, { useState } from 'react';
import { TouchableOpacity, Text, View, StyleSheet } from 'react-native';
const ColorChanger = () => {
  const [bgColor, setBgColor] = useState('white');
  return (
    <TouchableOpacity style={[styles.box, { backgroundColor: bgColor }]} onPress={() => setBgColor('lightgreen')}>
      <Text>Tap to change color</Text>
    </TouchableOpacity>
  );
};
const styles = StyleSheet.create({ box: { padding: 20, margin: 20 } });
export default ColorChanger;

8. Make an HTTP GET request using fetch and display the result.

jsx

import React, { useState, useEffect } from 'react';
import { Text, View } from 'react-native';
const FetchExample = () => {
  const [data, setData] = useState(null);
  useEffect(() => {
    fetch('https://jsonplaceholder.typicode.com/todos/1')
      .then(res => res.json())
      .then(json => setData(json));
  }, []);
  return <View>{data && <Text>{data.title}</Text>}</View>;
};
export default FetchExample;

9. Use useEffect to log a message when the component mounts.

jsx

import React, { useEffect } from 'react';
import { Text } from 'react-native';
const MountLogger = () => {
  useEffect(() => {
    console.log('Component mounted');
  }, []);
  return <Text>Check console</Text>;
};
export default MountLogger;

10. Create a toggle button that shows/hides a text using useState.

jsx

import React, { useState } from 'react';
import { View, Text, Button } from 'react-native';
const ToggleText = () => {
  const [visible, setVisible] = useState(false);
  return (
    <View>
      <Button title="Toggle" onPress={() => setVisible(!visible)} />
      {visible && <Text>Now you see me!</Text>}
    </View>
  );
};
export default ToggleText;

11. Implement a simple form with two TextInputs (email and password) and a submit button.

jsx

import React, { useState } from 'react';
import { View, TextInput, Button, Alert } from 'react-native';
const LoginForm = () => {
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const handleSubmit = () => Alert.alert(`Email: ${email}, Password: ${password}`);
  return (
    <View>
      <TextInput placeholder="Email" onChangeText={setEmail} />
      <TextInput placeholder="Password" secureTextEntry onChangeText={setPassword} />
      <Button title="Submit" onPress={handleSubmit} />
    </View>
  );
};
export default LoginForm;

12. Use FlatList with a separator component.

jsx

import React from 'react';
import { FlatList, Text, View } from 'react-native';
const data = [{ id: '1', name: 'A' }, { id: '2', name: 'B' }];
const ItemSeparator = () => <View style={{ height: 1, backgroundColor: 'gray' }} />;
const ListWithSeparator = () => (
  <FlatList
    data={data}
    renderItem={({ item }) => <Text>{item.name}</Text>}
    keyExtractor={item => item.id}
    ItemSeparatorComponent={ItemSeparator}
  />
);
export default ListWithSeparator;

13. Create a custom hook useToggle that returns a boolean and a toggle function.

jsx

import { useState } from 'react';
const useToggle = (initial = false) => {
  const [value, setValue] = useState(initial);
  const toggle = () => setValue(v => !v);
  return [value, toggle];
};
// Usage in component
const ToggleComponent = () => {
  const [isOn, toggle] = useToggle();
  return <Text onPress={toggle}>{isOn ? 'ON' : 'OFF'}</Text>;
};
export default ToggleComponent;

14. Use ScrollView to display a long list of text items.

jsx

import React from 'react';
import { ScrollView, Text } from 'react-native';
const LongScroll = () => (
  <ScrollView>
    {[...Array(50)].map((_, i) => <Text key={i}>Item {i + 1}</Text>)}
  </ScrollView>
);
export default LongScroll;

15. Apply a linear gradient using expo-linear-gradient (assume installed).

jsx

import React from 'react';
import { LinearGradient } from 'expo-linear-gradient';
import { Text } from 'react-native';
const GradientBox = () => (
  <LinearGradient colors={['#4c669f', '#3b5998']} style={{ padding: 20 }}>
    <Text>Gradient Background</Text>
  </LinearGradient>
);
export default GradientBox;

16. Use Alert.alert to show a confirmation before deleting an item.

jsx

import { Alert, Button } from 'react-native';
const DeleteButton = () => {
  const confirmDelete = () => {
    Alert.alert('Delete', 'Are you sure?', [
      { text: 'Cancel' },
      { text: 'OK', onPress: () => console.log('Deleted') }
    ]);
  };
  return <Button title="Delete" onPress={confirmDelete} />;
};
export default DeleteButton;

17. Implement a simple tab navigation using @react-navigation/bottom-tabs.

jsx

import { NavigationContainer } from '@react-navigation/native';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { Text } from 'react-native';
const HomeScreen = () => <Text>Home</Text>;
const SettingsScreen = () => <Text>Settings</Text>;
const Tab = createBottomTabNavigator();
export default function App() {
  return (
    <NavigationContainer>
      <Tab.Navigator>
        <Tab.Screen name="Home" component={HomeScreen} />
        <Tab.Screen name="Settings" component={SettingsScreen} />
      </Tab.Navigator>
    </NavigationContainer>
  );
}

18. Use useRef to focus a TextInput on button press.

jsx

import React, { useRef } from 'react';
import { TextInput, Button, View } from 'react-native';
const FocusInput = () => {
  const inputRef = useRef(null);
  return (
    <View>
      <TextInput ref={inputRef} placeholder="Focus me" />
      <Button title="Focus" onPress={() => inputRef.current.focus()} />
    </View>
  );
};
export default FocusInput;

19. Display a loading indicator while fetching data.

jsx

import React, { useState, useEffect } from 'react';
import { ActivityIndicator, Text, View } from 'react-native';
const LoadingData = () => {
  const [loading, setLoading] = useState(true);
  useEffect(() => {
    setTimeout(() => setLoading(false), 2000);
  }, []);
  return loading ? <ActivityIndicator size="large" /> : <Text>Data loaded</Text>;
};
export default LoadingData;

20. Use SafeAreaView to avoid notches on modern phones.

jsx

import React from 'react';
import { SafeAreaView, Text } from 'react-native';
const SafeAreaExample = () => (
  <SafeAreaView style={{ flex: 1 }}>
    <Text>Safe area content</Text>
  </SafeAreaView>
);
export default SafeAreaExample;

21. Create a component that uses Image to display a local image.

jsx

import React from 'react';
import { Image } from 'react-native';
const LocalImage = () => <Image source={require('./assets/icon.png')} style={{ width: 50, height: 50 }} />;
export default LocalImage;

22. Use Modal to show a popup when a button is pressed.

jsx

import React, { useState } from 'react';
import { Modal, View, Text, Button } from 'react-native';
const PopupModal = () => {
  const [visible, setVisible] = useState(false);
  return (
    <View>
      <Button title="Show Modal" onPress={() => setVisible(true)} />
      <Modal visible={visible} transparent animationType="slide">
        <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: 'rgba(0,0,0,0.5)' }}>
          <View style={{ backgroundColor: 'white', padding: 20 }}>
            <Text>Modal Content</Text>
            <Button title="Close" onPress={() => setVisible(false)} />
          </View>
        </View>
      </Modal>
    </View>
  );
};
export default PopupModal;

23. Save and retrieve data using AsyncStorage (React Native community).

jsx

import React, { useState, useEffect } from 'react';
import { View, TextInput, Button, Text } from 'react-native';
import AsyncStorage from '@react-native-async-storage/async-storage';
const StorageExample = () => {
  const [name, setName] = useState('');
  const [saved, setSaved] = useState('');
  useEffect(() => {
    AsyncStorage.getItem('name').then(val => setSaved(val || ''));
  }, []);
  const saveName = async () => {
    await AsyncStorage.setItem('name', name);
    setSaved(name);
  };
  return (
    <View>
      <TextInput placeholder="Enter name" onChangeText={setName} />
      <Button title="Save" onPress={saveName} />
      <Text>Saved: {saved}</Text>
    </View>
  );
};
export default StorageExample;

24. Use StatusBar to set the status bar style to light content.

jsx

import React from 'react';
import { StatusBar, View } from 'react-native';
const StatusBarExample = () => (
  <View>
    <StatusBar barStyle="light-content" />
  </View>
);
export default StatusBarExample;

25. Implement a horizontal FlatList using horizontal prop.

jsx

import React from 'react';
import { FlatList, Text, View } from 'react-native';
const data = [{ id: '1', color: 'red' }, { id: '2', color: 'blue' }];
const HorizontalList = () => (
  <FlatList horizontal data={data} renderItem={({ item }) => <View style={{ width: 100, height: 100, backgroundColor: item.color }} />} keyExtractor={item => item.id} />
);
export default HorizontalList;

26. Use Dimensions API to get screen width and set element size.

jsx

import React from 'react';
import { Dimensions, View } from 'react-native';
const { width } = Dimensions.get('window');
const FullWidthBox = () => <View style={{ width: width, height: 50, backgroundColor: 'green' }} />;
export default FullWidthBox;

27. Create a button that opens a URL in the device browser using Linking.

jsx

import React from 'react';
import { Button, Linking } from 'react-native';
const OpenLink = () => (
  <Button title="Open Google" onPress={() => Linking.openURL('https://www.google.com')} />
);
export default OpenLink;

28. Use useCallback to memoize a function passed to a child component.

jsx

import React, { useState, useCallback } from 'react';
import { Button, Text } from 'react-native';
const Child = ({ onPress }) => <Button title="Press" onPress={onPress} />;
const Parent = () => {
  const [count, setCount] = useState(0);
  const handlePress = useCallback(() => setCount(c => c + 1), []);
  return (
    <>
      <Text>{count}</Text>
      <Child onPress={handlePress} />
    </>
  );
};
export default Parent;

29. Handle network errors in fetch with .catch and display error message.

jsx

import React, { useState } from 'react';
import { Button, Text } from 'react-native';
const ErrorHandling = () => {
  const [error, setError] = useState('');
  const fetchData = () => {
    fetch('https://invalid.url')
      .then(res => res.json())
      .catch(err => setError(err.message));
  };
  return (
    <>
      <Button title="Fetch" onPress={fetchData} />
      {error ? <Text>Error: {error}</Text> : null}
    </>
  );
};
export default ErrorHandling;

30. Implement pull-to-refresh using RefreshControl inside FlatList.

jsx

import React, { useState } from 'react';
import { FlatList, RefreshControl, Text } from 'react-native';
const PullToRefresh = () => {
  const [refreshing, setRefreshing] = useState(false);
  const [data, setData] = useState(['Item 1', 'Item 2']);
  const onRefresh = () => {
    setRefreshing(true);
    setTimeout(() => {
      setData(['Item 1', 'Item 2', 'Item 3']);
      setRefreshing(false);
    }, 1000);
  };
  return (
    <FlatList
      data={data}
      renderItem={({ item }) => <Text>{item}</Text>}
      refreshControl={<RefreshControl refreshing={refreshing} onRefresh={onRefresh} />}
    />
  );
};
export default PullToRefresh;

31. Use Switch component to toggle a boolean state.

jsx

import React, { useState } from 'react';
import { Switch, Text, View } from 'react-native';
const ToggleSwitch = () => {
  const [isEnabled, setIsEnabled] = useState(false);
  return (
    <View>
      <Switch value={isEnabled} onValueChange={setIsEnabled} />
      <Text>{isEnabled ? 'ON' : 'OFF'}</Text>
    </View>
  );
};
export default ToggleSwitch;

32. Position an absolute element at bottom right using position: 'absolute'.

jsx

import React from 'react';
import { View, Text } from 'react-native';
const AbsoluteBox = () => (
  <View style={{ flex: 1 }}>
    <Text style={{ position: 'absolute', bottom: 10, right: 10 }}>Bottom Right</Text>
  </View>
);
export default AbsoluteBox;

33. Create a simple animation that fades in a view using Animated.

jsx

import React, { useEffect, useRef } from 'react';
import { Animated, View } from 'react-native';
const FadeIn = () => {
  const fadeAnim = useRef(new Animated.Value(0)).current;
  useEffect(() => {
    Animated.timing(fadeAnim, { toValue: 1, duration: 1000, useNativeDriver: true }).start();
  }, []);
  return <Animated.View style={{ opacity: fadeAnim, width: 100, height: 100, backgroundColor: 'red' }} />;
};
export default FadeIn;

34. Use KeyboardAvoidingView to move the screen when keyboard appears.

jsx

import React from 'react';
import { KeyboardAvoidingView, TextInput, Platform } from 'react-native';
const AvoidKeyboard = () => (
  <KeyboardAvoidingView behavior={Platform.OS === 'ios' ? 'padding' : 'height'} style={{ flex: 1 }}>
    <TextInput placeholder="Type here" style={{ marginTop: 400 }} />
  </KeyboardAvoidingView>
);
export default AvoidKeyboard;

35. Implement a countdown timer using useState and useEffect with setInterval.

jsx

import React, { useState, useEffect } from 'react';
import { Text } from 'react-native';
const Countdown = ({ seconds }) => {
  const [time, setTime] = useState(seconds);
  useEffect(() => {
    if (time <= 0) return;
    const interval = setInterval(() => setTime(t => t - 1), 1000);
    return () => clearInterval(interval);
  }, [time]);
  return <Text>Time left: {time}</Text>;
};
export default Countdown;

36. Use Picker from @react-native-picker/picker to select an option.

jsx

import React, { useState } from 'react';
import { Picker } from '@react-native-picker/picker';
const SelectExample = () => {
  const [selected, setSelected] = useState('apple');
  return (
    <Picker selectedValue={selected} onValueChange={setSelected}>
      <Picker.Item label="Apple" value="apple" />
      <Picker.Item label="Banana" value="banana" />
    </Picker>
  );
};
export default SelectExample;

37. Create a component that uses useLayoutEffect to measure a view’s dimensions.

jsx

import React, { useLayoutEffect, useState } from 'react';
import { View, Text } from 'react-native';
const MeasureExample = () => {
  const [width, setWidth] = useState(0);
  useLayoutEffect(() => {
    // measurement would require onLayout, but for demo:
    // just set a value
    setWidth(100);
  }, []);
  return <View><Text>Width: {width}</Text></View>;
};
export default MeasureExample;

38. Use FlatList with onEndReached to load more data (infinite scroll).

jsx

import React, { useState } from 'react';
import { FlatList, Text } from 'react-native';
const InfiniteScroll = () => {
  const [items, setItems] = useState([...Array(20).keys()]);
  const loadMore = () => setItems([...items, ...Array(10).keys()]);
  return (
    <FlatList
      data={items}
      renderItem={({ item }) => <Text>Item {item}</Text>}
      onEndReached={loadMore}
      onEndReachedThreshold={0.5}
    />
  );
};
export default InfiniteScroll;

39. Use TouchableHighlight to show underlay color when pressed.

jsx

import React from 'react';
import { TouchableHighlight, Text } from 'react-native';
const HighlightButton = () => (
  <TouchableHighlight underlayColor="lightgray" onPress={() => {}}>
    <Text>Press me</Text>
  </TouchableHighlight>
);
export default HighlightButton;

40. Use Clipboard from @react-native-clipboard/clipboard to copy text.

jsx

import React from 'react';
import { Button, Alert } from 'react-native';
import Clipboard from '@react-native-clipboard/clipboard';
const CopyText = () => {
  const copy = () => {
    Clipboard.setString('Hello');
    Alert.alert('Copied!');
  };
  return <Button title="Copy" onPress={copy} />;
};
export default CopyText;

41. Display an image from a URL with a placeholder using Image props (onLoadStart, onLoadEnd).

jsx

import React, { useState } from 'react';
import { Image, ActivityIndicator } from 'react-native';
const RemoteImage = () => {
  const [loading, setLoading] = useState(true);
  return (
    <>
      {loading && <ActivityIndicator />}
      <Image
        source={{ uri: 'https://example.com/image.jpg' }}
        onLoadStart={() => setLoading(true)}
        onLoadEnd={() => setLoading(false)}
        style={{ width: 100, height: 100 }}
      />
    </>
  );
};
export default RemoteImage;

42. Use React.memo to prevent unnecessary re-renders of a component.

jsx

import React, { useState } from 'react';
import { Text, Button } from 'react-native';
const Child = React.memo(({ count }) => <Text>Count: {count}</Text>);
const Parent = () => {
  const [count, setCount] = useState(0);
  return (
    <>
      <Child count={count} />
      <Button title="Increment" onPress={() => setCount(c => c + 1)} />
    </>
  );
};
export default Parent;

43. Create a custom View that responds to touch movement using PanResponder.

jsx

import React, { useRef } from 'react';
import { PanResponder, View, Animated } from 'react-native';
const DraggableBox = () => {
  const pan = useRef(new Animated.ValueXY()).current;
  const panResponder = PanResponder.create({
    onMoveShouldSetPanResponder: () => true,
    onPanResponderMove: Animated.event([null, { dx: pan.x, dy: pan.y }], { useNativeDriver: false }),
    onPanResponderRelease: () => Animated.spring(pan, { toValue: { x: 0, y: 0 }, useNativeDriver: false }).start()
  });
  return (
    <Animated.View style={{ transform: pan.getTranslateTransform(), width: 100, height: 100, backgroundColor: 'red' }} {...panResponder.panHandlers} />
  );
};
export default DraggableBox;

44. Use Alert.prompt (iOS only) to get user input.

jsx

import { Alert, Button } from 'react-native';
const PromptExample = () => (
  <Button title="Ask name" onPress={() => Alert.prompt('Enter name', undefined, text => console.log(text))} />
);
export default PromptExample;

45. Implement a simple useReducer example for a counter.

jsx

import React, { useReducer } from 'react';
import { Text, Button } from 'react-native';
const reducer = (state, action) => {
  switch (action.type) {
    case 'increment': return { count: state.count + 1 };
    default: return state;
  }
};
const CounterReducer = () => {
  const [state, dispatch] = useReducer(reducer, { count: 0 });
  return (
    <>
      <Text>{state.count}</Text>
      <Button title="+" onPress={() => dispatch({ type: 'increment' })} />
    </>
  );
};
export default CounterReducer;

46. Use Platform.select to choose different styles per platform.

jsx

import React from 'react';
import { View, Text, Platform } from 'react-native';
const PlatformStyle = () => (
  <View style={Platform.select({ ios: { backgroundColor: 'blue' }, android: { backgroundColor: 'green' } })}>
    <Text>Platform specific style</Text>
  </View>
);
export default PlatformStyle;

47. Create a component that uses BackHandler to handle Android back button.

jsx

import React, { useEffect } from 'react';
import { BackHandler, Alert } from 'react-native';
const BackHandlerExample = () => {
  useEffect(() => {
    const backAction = () => {
      Alert.alert('Exit', 'Are you sure?', [{ text: 'Cancel', style: 'cancel' }, { text: 'OK', onPress: () => BackHandler.exitApp() }]);
      return true;
    };
    const listener = BackHandler.addEventListener('hardwareBackPress', backAction);
    return () => listener.remove();
  }, []);
  return null;
};
export default BackHandlerExample;

48. Use Linking to open phone dialer with a number.

jsx

import React from 'react';
import { Button, Linking } from 'react-native';
const CallButton = () => (
  <Button title="Call" onPress={() => Linking.openURL('tel:1234567890')} />
);
export default CallButton;

Also try it: 100 kotlin practice problems with solutions

49. Create a SplashScreen that hides after 2 seconds using useEffect.

jsx

import React, { useEffect } from 'react';
import { View, Text } from 'react-native';
const Splash = ({ navigation }) => {
  useEffect(() => {
    setTimeout(() => navigation.replace('Home'), 2000);
  }, []);
  return (
    <View><Text>Splash Screen</Text></View>
  );
};
export default Splash;

50. Use InteractionManager to run code after interactions/animation complete.

jsx

import React, { useEffect } from 'react';
import { InteractionManager, Text } from 'react-native';
const AfterInteraction = () => {
  useEffect(() => {
    InteractionManager.runAfterInteractions(() => console.log('Interactions done'));
  }, []);
  return <Text>App is interactive</Text>;
};
export default AfterInteraction;

51. Use Vibration to trigger a short vibration.

jsx

import React from 'react';
import { Button, Vibration } from 'react-native';
const VibrateButton = () => (
  <Button title="Vibrate" onPress={() => Vibration.vibrate(200)} />
);
export default VibrateButton;

52. Create a component that uses DeviceEventEmitter to listen to custom events (iOS/Android).

jsx

import React, { useEffect } from 'react';
import { DeviceEventEmitter } from 'react-native';
const EventListener = () => {
  useEffect(() => {
    const subscription = DeviceEventEmitter.addListener('customEvent', (data) => console.log(data));
    return () => subscription.remove();
  }, []);
  return null;
};
export default EventListener;

53. Use PermissionsAndroid to request camera permission.

jsx

import React from 'react';
import { Button, PermissionsAndroid } from 'react-native';
const RequestCamera = async () => {
  const granted = await PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.CAMERA);
  console.log(granted);
};
const CameraButton = () => <Button title="Request Camera" onPress={RequestCamera} />;
export default CameraButton;

54. Use Share to share text or url.

jsx

import React from 'react';
import { Button, Share } from 'react-native';
const ShareExample = () => {
  const onShare = async () => {
    await Share.share({ message: 'Check this out!' });
  };
  return <Button title="Share" onPress={onShare} />;
};
export default ShareExample;

55. Implement a Slider from @react-native-community/slider to change a value.

jsx

import React, { useState } from 'react';
import { Slider } from '@react-native-community/slider';
import { Text } from 'react-native';
const SliderExample = () => {
  const [value, setValue] = useState(0.5);
  return (
    <>
      <Slider value={value} onValueChange={setValue} />
      <Text>Value: {value}</Text>
    </>
  );
};
export default SliderExample;

56. Use WebView from react-native-webview to load a website.

jsx

import React from 'react';
import { WebView } from 'react-native-webview';
const WebViewExample = () => <WebView source={{ uri: 'https://reactnative.dev' }} />;
export default WebViewExample;

57. Create a custom hook useDimensions that returns screen dimensions and updates on rotation.

jsx

import { useState, useEffect } from 'react';
import { Dimensions } from 'react-native';
const useDimensions = () => {
  const [dimensions, setDimensions] = useState(Dimensions.get('window'));
  useEffect(() => {
    const subscription = Dimensions.addEventListener('change', ({ window }) => setDimensions(window));
    return () => subscription?.remove();
  }, []);
  return dimensions;
};
// Usage in component
const ResponsiveBox = () => {
  const { width } = useDimensions();
  return <View style={{ width: width / 2, height: 50, backgroundColor: 'blue' }} />;
};
export default ResponsiveBox;

58. Use useImperativeHandle to expose a method to parent component.

jsx

import React, { useRef, useImperativeHandle, forwardRef } from 'react';
import { Button } from 'react-native';
const Child = forwardRef((props, ref) => {
  useImperativeHandle(ref, () => ({
    alertHello: () => alert('Hello'),
  }));
  return null;
});
const Parent = () => {
  const childRef = useRef();
  return <Button title="Call Child" onPress={() => childRef.current.alertHello()}><Child ref={childRef} /></Button>;
};
export default Parent;

59. Implement a simple network logger using XMLHttpRequest (to show response).

jsx

import React from 'react';
import { Button } from 'react-native';
const XHRExample = () => {
  const load = () => {
    const xhr = new XMLHttpRequest();
    xhr.onload = () => console.log(xhr.responseText);
    xhr.open('GET', 'https://jsonplaceholder.typicode.com/todos/1');
    xhr.send();
  };
  return <Button title="Fetch with XHR" onPress={load} />;
};
export default XHRExample;

60. Use SectionList to display grouped data.

jsx

import React from 'react';
import { SectionList, Text } from 'react-native';
const sections = [{ title: 'Fruits', data: ['Apple', 'Banana'] }, { title: 'Vegetables', data: ['Carrot', 'Broccoli'] }];
const GroupedList = () => (
  <SectionList
    sections={sections}
    renderItem={({ item }) => <Text>{item}</Text>}
    renderSectionHeader={({ section }) => <Text style={{ fontWeight: 'bold' }}>{section.title}</Text>}
    keyExtractor={(item, index) => index}
  />
);
export default GroupedList;

61. Create a component that uses AppState to detect when app goes to background.

jsx

import React, { useEffect } from 'react';
import { AppState, Text } from 'react-native';
const AppStateTracker = () => {
  useEffect(() => {
    const subscription = AppState.addEventListener('change', state => console.log('App state:', state));
    return () => subscription.remove();
  }, []);
  return <Text>Check console</Text>;
};
export default AppStateTracker;

62. Use Keyboard to dismiss keyboard when tapping outside a TextInput.

jsx

import React from 'react';
import { Keyboard, TouchableWithoutFeedback, TextInput, View } from 'react-native';
const DismissKeyboard = () => (
  <TouchableWithoutFeedback onPress={Keyboard.dismiss}>
    <View style={{ flex: 1 }}>
      <TextInput placeholder="Tap outside to dismiss" />
    </View>
  </TouchableWithoutFeedback>
);
export default DismissKeyboard;

63. Use UIManager to measure a component’s position on screen.

jsx

import React, { useRef } from 'react';
import { UIManager, findNodeHandle, Text, Button } from 'react-native';
const MeasureComponent = () => {
  const ref = useRef();
  const measure = () => {
    const node = findNodeHandle(ref.current);
    UIManager.measure(node, (x, y, width, height, pageX, pageY) => console.log({ pageX, pageY }));
  };
  return (
    <>
      <Text ref={ref}>Measure me</Text>
      <Button title="Measure" onPress={measure} />
    </>
  );
};
export default MeasureComponent;

64. Use NetInfo to check network connectivity.

jsx

import React, { useEffect, useState } from 'react';
import { Text } from 'react-native';
import NetInfo from '@react-native-community/netinfo';
const NetworkStatus = () => {
  const [isConnected, setIsConnected] = useState(true);
  useEffect(() => {
    const unsubscribe = NetInfo.addEventListener(state => setIsConnected(state.isConnected));
    return unsubscribe;
  }, []);
  return <Text>{isConnected ? 'Online' : 'Offline'}</Text>;
};
export default NetworkStatus;

65. Create a component that uses FlatList with sticky headers (using stickyHeaderIndices).

jsx

import React from 'react';
import { FlatList, Text } from 'react-native';
const data = ['Header', 'Item 1', 'Item 2'];
const StickyHeader = () => (
  <FlatList data={data} stickyHeaderIndices={[0]} renderItem={({ item }) => <Text style={{ padding: 10 }}>{item}</Text>} />
);
export default StickyHeader;

66. Use TouchableNativeFeedback (Android only) for ripple effect.

jsx

import React from 'react';
import { TouchableNativeFeedback, Text } from 'react-native';
const RippleButton = () => (
  <TouchableNativeFeedback onPress={() => {}}>
    <Text style={{ padding: 10 }}>Ripple effect</Text>
  </TouchableNativeFeedback>
);
export default RippleButton;

67. Implement a simple useInterval custom hook.

jsx

import { useEffect, useRef } from 'react';
const useInterval = (callback, delay) => {
  const savedCallback = useRef();
  useEffect(() => { savedCallback.current = callback; }, [callback]);
  useEffect(() => {
    if (delay !== null) {
      const id = setInterval(() => savedCallback.current(), delay);
      return () => clearInterval(id);
    }
  }, [delay]);
};
// Usage
const IntervalComponent = () => {
  useInterval(() => console.log('tick'), 1000);
  return null;
};
export default IntervalComponent;

68. Use ToastAndroid to show a toast on Android.

jsx

import React from 'react';
import { Button, ToastAndroid } from 'react-native';
const ToastExample = () => (
  <Button title="Show Toast" onPress={() => ToastAndroid.show('Hello', ToastAndroid.SHORT)} />
);
export default ToastExample;

69. Implement a basic drawer navigation using @react-navigation/drawer.

jsx

import { NavigationContainer } from '@react-navigation/native';
import { createDrawerNavigator } from '@react-navigation/drawer';
import { Text } from 'react-native';
const Home = () => <Text>Home</Text>;
const Settings = () => <Text>Settings</Text>;
const Drawer = createDrawerNavigator();
export default () => (
  <NavigationContainer>
    <Drawer.Navigator>
      <Drawer.Screen name="Home" component={Home} />
      <Drawer.Screen name="Settings" component={Settings} />
    </Drawer.Navigator>
  </NavigationContainer>
);

70. Use useWindowDimensions to get reactive window dimensions.

jsx

import React from 'react';
import { useWindowDimensions, Text } from 'react-native';
const WindowInfo = () => {
  const { width, height } = useWindowDimensions();
  return <Text>Width: {width}, Height: {height}</Text>;
};
export default WindowInfo;

71. Use ImageBackground to overlay text on an image.

jsx

import React from 'react';
import { ImageBackground, Text } from 'react-native';
const BgImage = () => (
  <ImageBackground source={require('./assets/bg.jpg')} style={{ width: 200, height: 100 }}>
    <Text>Overlay text</Text>
  </ImageBackground>
);
export default BgImage;

72. Create a component that uses Button with disabled prop to prevent multiple taps.

jsx

import React, { useState } from 'react';
import { Button } from 'react-native';
const DisableButton = () => {
  const [disabled, setDisabled] = useState(false);
  const handlePress = () => {
    setDisabled(true);
    setTimeout(() => setDisabled(false), 2000);
  };
  return <Button title="Press" onPress={handlePress} disabled={disabled} />;
};
export default DisableButton;

73. Use AccessibilityInfo to announce a message when something happens.

jsx

import React from 'react';
import { Button, AccessibilityInfo } from 'react-native';
const Announce = () => (
  <Button title="Announce" onPress={() => AccessibilityInfo.announceForAccessibility('Button pressed')} />
);
export default Announce;

74. Use Easing from react-native-reanimated for custom animation curves.

jsx

import Animated, { Easing } from 'react-native-reanimated';
const { timing } = Animated;
// Example usage in component
const CustomEasing = () => {
  const anim = new Animated.Value(0);
  Animated.timing(anim, { toValue: 1, duration: 1000, easing: Easing.bounce, useNativeDriver: true }).start();
  return <Animated.View style={{ opacity: anim, width: 100, height: 100, backgroundColor: 'red' }} />;
};
export default CustomEasing;

75. Create a component that uses FlatList with dynamic row height (automatic).

jsx

import React from 'react';
import { FlatList, Text, View } from 'react-native';
const data = [{ id: '1', text: 'short' }, { id: '2', text: 'very long text that wraps multiple lines' }];
const DynamicHeight = () => (
  <FlatList data={data} renderItem={({ item }) => <View style={{ padding: 10 }}><Text>{item.text}</Text></View>} keyExtractor={item => item.id} />
);
export default DynamicHeight;

76. Implement a simple “like” button that toggles heart icon using FontAwesome from react-native-vector-icons.

jsx

import React, { useState } from 'react';
import { TouchableOpacity } from 'react-native';
import Icon from 'react-native-vector-icons/FontAwesome';
const LikeButton = () => {
  const [liked, setLiked] = useState(false);
  return (
    <TouchableOpacity onPress={() => setLiked(!liked)}>
      <Icon name={liked ? 'heart' : 'heart-o'} size={30} color="red" />
    </TouchableOpacity>
  );
};
export default LikeButton;

77. Use CameraRoll from @react-native-community/cameraroll to save an image.

jsx

import { CameraRoll } from '@react-native-community/cameraroll';
const saveImage = async (uri) => {
  await CameraRoll.save(uri, { type: 'photo' });
};

78. Use KeyboardAvoidingView with ScrollView to ensure input visible.

jsx

import React from 'react';
import { KeyboardAvoidingView, ScrollView, TextInput } from 'react-native';
const FormWithScroll = () => (
  <KeyboardAvoidingView style={{ flex: 1 }} behavior="padding">
    <ScrollView>
      <TextInput placeholder="Field 1" />
      <TextInput placeholder="Field 2" />
    </ScrollView>
  </KeyboardAvoidingView>
);
export default FormWithScroll;

79. Create a custom StatusBar component that changes style based on current screen (using navigation events).

jsx

import React, { useEffect } from 'react';
import { StatusBar } from 'react-native';
import { useNavigation } from '@react-navigation/native';
const DynamicStatusBar = ({ barStyle }) => {
  const navigation = useNavigation();
  useEffect(() => {
    const unsubscribe = navigation.addListener('focus', () => StatusBar.setBarStyle(barStyle));
    return unsubscribe;
  }, [navigation, barStyle]);
  return null;
};
// Usage: <DynamicStatusBar barStyle="light-content" />
export default DynamicStatusBar;

80. Implement a simple form validation for email and password fields.

jsx

import React, { useState } from 'react';
import { View, TextInput, Button, Alert } from 'react-native';
const ValidatedForm = () => {
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const validate = () => {
    if (!email.includes('@')) return Alert.alert('Invalid email');
    if (password.length < 6) return Alert.alert('Password too short');
    Alert.alert('Success');
  };
  return (
    <View>
      <TextInput placeholder="Email" onChangeText={setEmail} />
      <TextInput placeholder="Password" secureTextEntry onChangeText={setPassword} />
      <Button title="Submit" onPress={validate} />
    </View>
  );
};
export default ValidatedForm;

81. Use Clipboard to read clipboard content.

jsx

import React from 'react';
import { Button, Alert } from 'react-native';
import Clipboard from '@react-native-clipboard/clipboard';
const ReadClipboard = () => {
  const read = async () => {
    const content = await Clipboard.getString();
    Alert.alert('Clipboard', content);
  };
  return <Button title="Read Clipboard" onPress={read} />;
};
export default ReadClipboard;

Also try it: 100 Swift practice problems with solutions

82. Implement a component that uses useDebugValue to label custom hook in DevTools.

jsx

import { useDebugValue, useState } from 'react';
const useFriendStatus = (friendId) => {
  const [isOnline, setIsOnline] = useState(false);
  useDebugValue(isOnline ? 'Online' : 'Offline');
  return isOnline;
};
// Usage in component
const FriendStatus = ({ id }) => {
  const online = useFriendStatus(id);
  return <Text>{online ? 'Online' : 'Offline'}</Text>;
};

83. Use InteractionManager to schedule a task after long list rendering.

jsx

import React, { useEffect, useState } from 'react';
import { InteractionManager, FlatList, Text } from 'react-native';
const HeavyList = () => {
  const [ready, setReady] = useState(false);
  useEffect(() => {
    InteractionManager.runAfterInteractions(() => setReady(true));
  }, []);
  return ready ? <FlatList data={[...Array(100).keys()]} renderItem={({ item }) => <Text>{item}</Text>} /> : <Text>Loading...</Text>;
};
export default HeavyList;

84. Use LayoutAnimation to animate layout changes (simple expand/collapse).

jsx

import React, { useState } from 'react';
import { LayoutAnimation, View, Button } from 'react-native';
const ExpandCollapse = () => {
  const [expanded, setExpanded] = useState(false);
  const toggle = () => {
    LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
    setExpanded(!expanded);
  };
  return (
    <View>
      <Button title="Toggle" onPress={toggle} />
      {expanded && <View style={{ height: 100, backgroundColor: 'blue' }} />}
    </View>
  );
};
export default ExpandCollapse;

85. Create a component that uses Image with resizeMode cover.

jsx

import React from 'react';
import { Image } from 'react-native';
const CoverImage = () => (
  <Image source={{ uri: 'https://picsum.photos/200/300' }} style={{ width: 200, height: 200 }} resizeMode="cover" />
);
export default CoverImage;

86. Use PixelRatio to get device pixel ratio.

jsx

import React from 'react';
import { PixelRatio, Text } from 'react-native';
const PixelInfo = () => <Text>Pixel ratio: {PixelRatio.get()}</Text>;
export default PixelInfo;

87. Implement a simple usePrevious hook to track previous value.

jsx

import { useRef, useEffect } from 'react';
const usePrevious = (value) => {
  const ref = useRef();
  useEffect(() => { ref.current = value; }, [value]);
  return ref.current;
};
// Usage
const PreviousExample = ({ count }) => {
  const prevCount = usePrevious(count);
  return <Text>Current: {count}, Previous: {prevCount}</Text>;
};
export default PreviousExample;

88. Use Platform.select to import different modules per platform.

jsx

const Component = Platform.select({
  ios: () => require('./iOSComponent').default,
  android: () => require('./AndroidComponent').default,
})();
export default Component;

89. Create a custom View that detects touch location using onStartShouldSetResponder.

jsx

import React from 'react';
import { View, Text } from 'react-native';
const TouchDetector = () => {
  const onTouch = (evt) => console.log('Touch at:', evt.nativeEvent.locationX);
  return (
    <View
      onStartShouldSetResponder={() => true}
      onResponderGrant={onTouch}
      style={{ width: 200, height: 200, backgroundColor: 'yellow' }}
    >
      <Text>Touch anywhere</Text>
    </View>
  );
};

90. Use useScrollToTop from @react-navigation/native to scroll to top when tapping active tab.

jsx

import React, { useRef } from 'react';
import { useScrollToTop } from '@react-navigation/native';
import { FlatList } from 'react-native';
const ScrollableScreen = () => {
  const ref = useRef(null);
  useScrollToTop(ref);
  return <FlatList ref={ref} data={[...Array(100).keys()]} renderItem={({ item }) => <Text>{item}</Text>} />;
};
export default ScrollableScreen;

91. Use ActionSheetIOS to show an action sheet on iOS.

jsx

import { ActionSheetIOS, Button } from 'react-native';
const ActionSheetExample = () => (
  <Button title="Show Action Sheet" onPress={() => ActionSheetIOS.showActionSheetWithOptions({ options: ['Option1', 'Cancel'], cancelButtonIndex: 1 }, (idx) => console.log(idx))} />
);
export default ActionSheetExample;

92. Implement a simple deep link handler using Linking event listener.

jsx

import React, { useEffect } from 'react';
import { Linking } from 'react-native';
const DeepLinkHandler = () => {
  useEffect(() => {
    const handleUrl = ({ url }) => console.log('Received url:', url);
    Linking.addEventListener('url', handleUrl);
    return () => Linking.removeEventListener('url', handleUrl);
  }, []);
  return null;
};
export default DeepLinkHandler;

93. Use Keyboard.dismiss with ScrollView prop keyboardShouldPersistTaps="handled".

jsx

import React from 'react';
import { Keyboard, ScrollView, TextInput, TouchableWithoutFeedback } from 'react-native';
const DismissScroll = () => (
  <TouchableWithoutFeedback onPress={Keyboard.dismiss}>
    <ScrollView keyboardShouldPersistTaps="handled">
      <TextInput />
      <TextInput />
    </ScrollView>
  </TouchableWithoutFeedback>
);
export default DismissScroll;

94. Use Pressable for advanced press states (hover, pressed).

jsx

import React from 'react';
import { Pressable, Text } from 'react-native';
const PressableExample = () => (
  <Pressable onPress={() => {}} style={({ pressed }) => ({ opacity: pressed ? 0.5 : 1 })}>
    <Text>Press me</Text>
  </Pressable>
);
export default PressableExample;

95. Use refreshControl inside ScrollView (not just FlatList).

jsx

import React, { useState } from 'react';
import { ScrollView, RefreshControl, Text } from 'react-native';
const ScrollRefresh = () => {
  const [refreshing, setRefreshing] = useState(false);
  const onRefresh = () => {
    setRefreshing(true);
    setTimeout(() => setRefreshing(false), 1000);
  };
  return (
    <ScrollView refreshControl={<RefreshControl refreshing={refreshing} onRefresh={onRefresh} />}>
      <Text>Pull to refresh</Text>
    </ScrollView>
  );
};
export default ScrollRefresh;

96. Create a component that uses FlatList with getItemLayout for performance.

jsx

import React from 'react';
import { FlatList, Text } from 'react-native';
const data = Array.from({ length: 1000 }, (_, i) => `Item ${i}`);
const OptimizedList = () => (
  <FlatList
    data={data}
    renderItem={({ item }) => <Text>{item}</Text>}
    getItemLayout={(data, index) => ({ length: 40, offset: 40 * index, index })}
  />
);
export default OptimizedList;

97. Use InAppBrowser from react-native-inappbrowser-reborn to open a URL in app.

jsx

import { InAppBrowser } from 'react-native-inappbrowser-reborn';
const openUrl = async (url) => {
  if (await InAppBrowser.isAvailable()) {
    await InAppBrowser.open(url);
  }
};

98. Use BackgroundTimer from react-native-background-timer to run periodic tasks in background.

jsx

import BackgroundTimer from 'react-native-background-timer';
BackgroundTimer.setTimeout(() => console.log('Background task'), 1000);

99. Implement a component that uses React.forwardRef to forward a ref to a child TextInput.

jsx

import React, { useRef } from 'react';
import { TextInput, Button } from 'react-native';
const FancyInput = React.forwardRef((props, ref) => <TextInput ref={ref} {...props} />);
const ParentComponent = () => {
  const inputRef = useRef();
  return (
    <>
      <FancyInput ref={inputRef} placeholder="Focus me" />
      <Button title="Focus" onPress={() => inputRef.current.focus()} />
    </>
  );
};
export default ParentComponent;

100. Use _ (lodash) debounce to prevent rapid button presses.

jsx

import React, { useCallback } from 'react';
import { Button } from 'react-native';
import debounce from 'lodash/debounce';
const DebouncedButton = () => {
  const handlePress = useCallback(debounce(() => console.log('Pressed'), 500), []);
  return <Button title="Press me" onPress={handlePress} />;
};
export default DebouncedButton;

Also try it: 100 C++ practice problems with solutions

Final Thought

One hundred problems. One hundred tiny battles with a blank screen, a cryptic red error, or a component that just refused to render. And you know what? You didn’t throw your laptop out the window — even if you wanted to. There’s a fire in you that’s part fury and part fierce, stubborn love. Love for the craft.

Love for that moment when the UI finally, beautifully, just works. And maybe a little anger too — anger at all the times you were made to feel “not technical enough,” anger at imposter syndrome hissing lies, anger that once fueled your focus until the bug was dead and the screen glowed with your own creation.

Use that fire. It’s not a weakness; it’s proof you care deeply. Keep building with love, keep debugging with that fire in your belly, and never let the grind steal the joy that made you open this post in the first place. The apps you’re going to build will matter — because you built them with both passion and persistence. Now go make something wonderful.



Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top