Bird
Raised Fist0
React Nativemobile~20 mins

Expo modules in React Native - Mini App: Build & Ship

Choose your learning style10 modes available
Build: Camera Capture Screen
This screen lets users take a photo using the device camera and shows the captured image on the screen.
Target UI
┌─────────────────────────────┐
│        Camera Capture        │
├─────────────────────────────┤
│                             │
│        [Camera View]         │
│                             │
│                             │
│                             │
│                             │
│                             │
├─────────────────────────────┤
│   [Take Photo Button]        │
└─────────────────────────────┘
Use Expo Camera module to show live camera preview.
Add a button labeled 'Take Photo' below the camera preview.
When the button is pressed, capture a photo and display it below the button.
If a photo is captured, show the image on the screen.
Request camera permissions on screen load and handle permission denial gracefully.
Starter Code
React Native
import React, { useState, useEffect, useRef } from 'react';
import { View, Text, Button, Image, StyleSheet } from 'react-native';
import { Camera } from 'expo-camera';

export default function CameraCaptureScreen() {
  const [hasPermission, setHasPermission] = useState(null);
  const [photoUri, setPhotoUri] = useState(null);
  const cameraRef = useRef(null);

  useEffect(() => {
    (async () => {
      // TODO: Request camera permissions here
    })();
  }, []);

  const takePhoto = async () => {
    // TODO: Capture photo and save URI
  };

  return (
    <View style={styles.container}>
      {/* TODO: Show camera preview if permission granted */}
      {/* TODO: Show message if permission denied or null */}
      {/* TODO: Add Take Photo button */}
      {/* TODO: Show captured photo if available */}
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    padding: 10
  },
  camera: {
    width: '100%',
    height: 300,
  },
  photo: {
    width: 300,
    height: 300,
    marginTop: 10
  }
});
Task 1
Task 2
Task 3
Task 4
Task 5
Task 6
Solution
React Native
import React, { useState, useEffect, useRef } from 'react';
import { View, Text, Button, Image, StyleSheet } from 'react-native';
import { Camera } from 'expo-camera';

export default function CameraCaptureScreen() {
  const [hasPermission, setHasPermission] = useState(null);
  const [photoUri, setPhotoUri] = useState(null);
  const cameraRef = useRef(null);

  useEffect(() => {
    (async () => {
      const { status } = await Camera.requestCameraPermissionsAsync();
      setHasPermission(status === 'granted');
    })();
  }, []);

  const takePhoto = async () => {
    if (cameraRef.current) {
      const photo = await cameraRef.current.takePictureAsync();
      setPhotoUri(photo.uri);
    }
  };

  if (hasPermission === null) {
    return <Text>Requesting camera permission...</Text>;
  }

  if (hasPermission === false) {
    return <Text>No access to camera. Please allow camera permission.</Text>;
  }

  return (
    <View style={styles.container}>
      <Camera style={styles.camera} ref={cameraRef} />
      <Button title="Take Photo" onPress={takePhoto} />
      {photoUri && <Image source={{ uri: photoUri }} style={styles.photo} />}
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    padding: 10
  },
  camera: {
    width: '100%',
    height: 300
  },
  photo: {
    width: 300,
    height: 300,
    marginTop: 10
  }
});

This solution uses the Expo Camera module to show a live camera preview. When the screen loads, it asks the user for camera permission. If permission is granted, the camera preview is shown. A button labeled 'Take Photo' lets the user capture a picture. The picture's URI is saved in state and displayed below the button as an image. If permission is denied or still loading, a friendly message is shown instead.

We use a ref to access the camera methods. The takePictureAsync() method captures the photo. The UI updates automatically to show the captured image. This app is simple and shows how to use Expo modules to access device features easily.

Final Result
Completed Screen
┌─────────────────────────────┐
│        Camera Capture        │
├─────────────────────────────┤
│  [Live Camera Preview Here] │
│                             │
│                             │
│                             │
│                             │
├─────────────────────────────┤
│   [Take Photo Button]        │
├─────────────────────────────┤
│  [Captured Photo Displayed]  │
│                             │
└─────────────────────────────┘
When the screen opens, it asks for camera permission.
If permission is granted, the live camera preview appears.
User taps 'Take Photo' button to capture an image.
The captured photo appears below the button.
If permission is denied, a message tells the user no access.
Stretch Goal
Add a button to switch between front and back cameras.
💡 Hint
Use Camera's 'type' prop and toggle between Camera.Constants.Type.front and Camera.Constants.Type.back.

Practice

(1/5)
1. What is the main purpose of Expo modules in a React Native app?
easy
A. To create custom UI components from scratch
B. To write backend server code
C. To manage app navigation between screens
D. To easily add device features like camera and location

Solution

  1. Step 1: Understand Expo modules role

    Expo modules provide access to device features such as camera, location, and notifications.
  2. Step 2: Compare options with this role

    Only To easily add device features like camera and location matches this purpose; others relate to UI, navigation, or backend, which Expo modules do not handle.
  3. Final Answer:

    To easily add device features like camera and location -> Option D
  4. Quick Check:

    Expo modules = device features access [OK]
Hint: Expo modules = device features access, not UI or backend [OK]
Common Mistakes:
  • Confusing Expo modules with navigation libraries
  • Thinking Expo modules create UI components
  • Assuming Expo modules handle backend logic
2. Which is the correct way to import the Camera module from Expo in a React Native app?
easy
A. import { Camera } from 'expo-camera';
B. import Camera from 'react-native-camera';
C. import { Camera } from 'expo-device';
D. import Camera from 'expo-camera-module';

Solution

  1. Step 1: Identify the official Expo Camera import

    The correct import is from 'expo-camera' with named import { Camera }.
  2. Step 2: Check other options for correctness

    import Camera from 'react-native-camera'; uses a different library name, C imports from wrong module, D uses a non-existent module name.
  3. Final Answer:

    import { Camera } from 'expo-camera'; -> Option A
  4. Quick Check:

    Expo Camera import = { Camera } from 'expo-camera' [OK]
Hint: Expo modules import from 'expo-<feature>' with named imports [OK]
Common Mistakes:
  • Using default import instead of named import
  • Importing from wrong package name
  • Confusing Expo modules with React Native community packages
3. What will the following code output if the user denies camera permission?
import { Camera } from 'expo-camera';
import React, { useState, useEffect } from 'react';

export default function App() {
  const [hasPermission, setHasPermission] = useState(null);

  useEffect(() => {
    (async () => {
      const { status } = await Camera.requestCameraPermissionsAsync();
      setHasPermission(status === 'granted');
    })();
  }, []);

  if (hasPermission === null) {
    return Requesting permission...;
  }
  if (hasPermission === false) {
    return No access to camera;
  }
  return Camera access granted;
}
medium
A. Displays 'No access to camera'
B. Displays 'Requesting permission...' indefinitely
C. Displays 'Camera access granted'
D. Throws a runtime error

Solution

  1. Step 1: Understand permission request flow

    The code requests camera permission asynchronously and sets hasPermission to true if granted, false otherwise.
  2. Step 2: Analyze user denies permission case

    If user denies, status !== 'granted', so hasPermission is false, triggering the second if block to show 'No access to camera'.
  3. Final Answer:

    Displays 'No access to camera' -> Option A
  4. Quick Check:

    User denies permission = show 'No access to camera' [OK]
Hint: Permission denied sets hasPermission false, shows denial message [OK]
Common Mistakes:
  • Assuming permission request never finishes
  • Confusing null and false states
  • Expecting granted message even if denied
4. Identify the error in this Expo Location usage code:
import * as Location from 'expo-location';
import React, { useState, useEffect } from 'react';

export default function App() {
  const [location, setLocation] = useState(null);

  useEffect(() => {
    (async () => {
      let { status } = await Location.requestForegroundPermissionsAsync();
      if (status !== 'granted') {
        return;
      }
      let loc = await Location.getCurrentPositionAsync({});
      setLocation(loc);
    })();
  }, []);

  return location ? {JSON.stringify(location)} : Loading...;
}
medium
A. Using getCurrentPositionAsync without options
B. Using useState incorrectly with null initial value
C. Missing parentheses when calling requestForegroundPermissionsAsync
D. Not importing React properly

Solution

  1. Step 1: Check async function calls

    The code uses await Location.requestForegroundPermissionsAsync without parentheses, so it references the function instead of calling it.
  2. Step 2: Verify other parts

    useState with null is valid, React import is correct, getCurrentPositionAsync can be called with empty options object.
  3. Final Answer:

    Missing parentheses when calling requestForegroundPermissionsAsync -> Option C
  4. Quick Check:

    Async function call needs () to execute [OK]
Hint: Async calls need () after function name to run [OK]
Common Mistakes:
  • Forgetting () on async function calls
  • Assuming useState(null) is wrong
  • Thinking getCurrentPositionAsync requires options
5. You want to build a React Native app using Expo modules that shows the user's current location only if permission is granted. Which sequence of steps is correct?
hard
A. Request permission first, then import Location module, then get location
B. Import Location module, request permission, check status, get location if granted, display location
C. Import Location module, get location immediately, then request permission if needed
D. Display location first, then request permission, then import Location module

Solution

  1. Step 1: Understand correct usage order

    You must import the Location module first to use its functions.
  2. Step 2: Request permission before accessing location

    Request permission and check status before calling getCurrentPositionAsync to avoid errors.
  3. Step 3: Only get and display location if permission is granted

    This ensures app behaves correctly and respects user privacy.
  4. Final Answer:

    Import Location module, request permission, check status, get location if granted, display location -> Option B
  5. Quick Check:

    Import -> request permission -> check -> get location -> display [OK]
Hint: Always request permission before accessing device features [OK]
Common Mistakes:
  • Trying to get location before permission
  • Requesting permission after accessing location
  • Importing modules after usage
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard