Bird
Raised Fist0
React Nativemobile~20 mins

AbortController for cancellation in React Native - Mini App: Build & Ship

Choose your learning style10 modes available
Build: Fetch Data with Cancel
This screen fetches data from a remote API and allows the user to cancel the fetch request anytime.
Target UI
-------------------------
| Fetch Data with Cancel |
-------------------------
| [Fetch Data Button]    |
|                       |
| Data:                  |
| <empty or fetched>     |
|                       |
| [Cancel Fetch Button]  |
-------------------------
Add a button labeled 'Fetch Data' that starts fetching data from https://jsonplaceholder.typicode.com/todos/1
Display the fetched data's title below the button
Add a 'Cancel Fetch' button that cancels the ongoing fetch request
Use AbortController to handle cancellation
Show 'Fetch cancelled' message if fetch is aborted
Disable 'Cancel Fetch' button when no fetch is running
Handle errors gracefully and show error messages
Starter Code
React Native
import React, { useState, useRef } from 'react';
import { View, Text, Button, StyleSheet } from 'react-native';

export default function FetchCancelScreen() {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);
  const [cancelled, setCancelled] = useState(false);
  const abortControllerRef = useRef(null);

  const fetchData = () => {
    // TODO: Implement fetch with AbortController
  };

  const cancelFetch = () => {
    // TODO: Implement cancellation
  };

  return (
    <View style={styles.container}>
      <Text style={styles.title}>Fetch Data with Cancel</Text>
      <Button title="Fetch Data" onPress={fetchData} disabled={loading} />
      <View style={styles.dataContainer}>
        {/* TODO: Show data, error, or cancelled message here */}
      </View>
      <Button title="Cancel Fetch" onPress={cancelFetch} disabled={!loading} />
    </View>
  );
}

const styles = StyleSheet.create({
  container: { flex: 1, padding: 20, justifyContent: 'center' },
  title: { fontSize: 24, fontWeight: 'bold', marginBottom: 20, textAlign: 'center' },
  dataContainer: { marginVertical: 20, minHeight: 50 },
});
Task 1
Task 2
Task 3
Task 4
Task 5
Task 6
Task 7
Solution
React Native
import React, { useState, useRef } from 'react';
import { View, Text, Button, StyleSheet } from 'react-native';

export default function FetchCancelScreen() {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);
  const [cancelled, setCancelled] = useState(false);
  const abortControllerRef = useRef(null);

  const fetchData = () => {
    setLoading(true);
    setError(null);
    setCancelled(false);
    setData(null);

    const controller = new AbortController();
    abortControllerRef.current = controller;

    fetch('https://jsonplaceholder.typicode.com/todos/1', { signal: controller.signal })
      .then(response => {
        if (!response.ok) throw new Error('Network response was not ok');
        return response.json();
      })
      .then(json => {
        setData(json.title);
        setError(null);
        setCancelled(false);
      })
      .catch(err => {
        if (err.name === 'AbortError') {
          setCancelled(true);
          setData(null);
          setError(null);
        } else {
          setError(err.message);
          setData(null);
          setCancelled(false);
        }
      })
      .finally(() => {
        setLoading(false);
        abortControllerRef.current = null;
      });
  };

  const cancelFetch = () => {
    if (abortControllerRef.current) {
      abortControllerRef.current.abort();
    }
  };

  return (
    <View style={styles.container}>
      <Text style={styles.title}>Fetch Data with Cancel</Text>
      <Button title="Fetch Data" onPress={fetchData} disabled={loading} />
      <View style={styles.dataContainer}>
        {loading && <Text>Loading...</Text>}
        {data && <Text>Data: {data}</Text>}
        {error && <Text style={{ color: 'red' }}>Error: {error}</Text>}
        {cancelled && <Text style={{ color: 'orange' }}>Fetch cancelled</Text>}
      </View>
      <Button title="Cancel Fetch" onPress={cancelFetch} disabled={!loading} />
    </View>
  );
}

const styles = StyleSheet.create({
  container: { flex: 1, padding: 20, justifyContent: 'center' },
  title: { fontSize: 24, fontWeight: 'bold', marginBottom: 20, textAlign: 'center' },
  dataContainer: { marginVertical: 20, minHeight: 50 },
});

We use AbortController to create a controller that can cancel the fetch request. We save it in a useRef so it persists between renders without causing re-renders.

When the user taps 'Fetch Data', we create a new controller and start fetching with its signal. We update states to show loading and clear previous data or errors.

If the fetch succeeds, we show the fetched title. If the fetch is aborted, we show a cancellation message. If any other error happens, we show the error message.

The 'Cancel Fetch' button calls abort() on the controller, which triggers the abort error and cancels the fetch.

We disable buttons appropriately to prevent multiple fetches or cancelling when no fetch is running.

Final Result
Completed Screen
-------------------------
| Fetch Data with Cancel |
-------------------------
| [Fetch Data Button]    |
|                       |
| Data: delectus aut au- |
| tem quia possimus sus- |
| cipit rerum consequun- |
| tur magni dolores eos  |
| qui ratione voluptatem |
| sequi nesciunt.        |
|                       |
| [Cancel Fetch Button]  |
-------------------------
Tap 'Fetch Data' starts loading and disables 'Fetch Data' button
Fetched data title appears below the button after success
Tap 'Cancel Fetch' during loading cancels fetch and shows 'Fetch cancelled'
'Cancel Fetch' button is disabled when no fetch is running
If fetch fails, error message appears in red text
Stretch Goal
Add a pull-to-refresh gesture to re-fetch data
💡 Hint
Use React Native's RefreshControl with ScrollView or FlatList and connect it to fetchData function

Practice

(1/5)
1. What is the main purpose of using AbortController in React Native fetch requests?
easy
A. To cancel an ongoing fetch request before it completes
B. To speed up the fetch request automatically
C. To retry a fetch request multiple times
D. To cache the fetch response for offline use

Solution

  1. Step 1: Understand what AbortController does

    AbortController provides a way to stop a fetch request that is still running.
  2. Step 2: Compare options with AbortController's purpose

    Only To cancel an ongoing fetch request before it completes describes stopping or canceling a fetch request early.
  3. Final Answer:

    To cancel an ongoing fetch request before it completes -> Option A
  4. Quick Check:

    AbortController cancels fetch = B [OK]
Hint: AbortController is for stopping fetch early [OK]
Common Mistakes:
  • Thinking it speeds up fetch automatically
  • Confusing cancellation with retry
  • Assuming it caches data
2. Which of the following is the correct way to create an AbortController and pass its signal to a fetch request?
easy
A. const controller = new AbortController(); fetch(url, { cancelToken: controller });
B. const controller = AbortController(); fetch(url, { abort: controller });
C. const controller = new AbortController(); fetch(url, { signal: controller })
D. const controller = new AbortController(); fetch(url, { signal: controller.signal });

Solution

  1. Step 1: Check how to instantiate AbortController

    It must be created with the new keyword: new AbortController().
  2. Step 2: Verify how to pass the signal to fetch

    The fetch option key is signal and its value is controller.signal.
  3. Final Answer:

    const controller = new AbortController(); fetch(url, { signal: controller.signal }); -> Option D
  4. Quick Check:

    Use new and pass signal property = C [OK]
Hint: Use new AbortController() and pass signal: controller.signal [OK]
Common Mistakes:
  • Omitting the new keyword
  • Passing controller instead of controller.signal
  • Using wrong option keys like abort or cancelToken
3. Consider this code snippet:
const controller = new AbortController();
fetch('https://example.com/data', { signal: controller.signal })
  .then(response => response.json())
  .then(data => console.log('Data:', data))
  .catch(error => console.log('Error:', error.name));

controller.abort();
What will be logged to the console?
medium
A. Error: AbortError
B. Data: [fetched data]
C. Error: TypeError
D. Nothing is logged

Solution

  1. Step 1: Understand what controller.abort() does

    Calling abort() cancels the fetch request, triggering an error with name 'AbortError'.
  2. Step 2: Check the catch block behavior

    The catch block logs the error name, so it will log 'AbortError'.
  3. Final Answer:

    Error: AbortError -> Option A
  4. Quick Check:

    Abort triggers AbortError catch = A [OK]
Hint: Aborting fetch triggers AbortError in catch [OK]
Common Mistakes:
  • Expecting data to log after abort
  • Confusing AbortError with TypeError
  • Thinking nothing logs on abort
4. You wrote this code but the fetch never cancels as expected:
const controller = new AbortController();
fetch('https://api.example.com', { signal: controller.signal });
// Some code
controller.abort();
What is the most likely reason the fetch is not canceled?
medium
A. You did not assign the signal property correctly
B. You called abort() before starting fetch
C. The fetch request already completed before abort() was called
D. You forgot to handle the abort error in catch block

Solution

  1. Step 1: Understand timing of abort()

    If abort() is called after fetch completes, it has no effect.
  2. Step 2: Check other options

    Signal is assigned correctly, and abort() is called after fetch starts, so those are not issues.
  3. Final Answer:

    The fetch request already completed before abort() was called -> Option C
  4. Quick Check:

    Abort after fetch finishes does nothing = A [OK]
Hint: Abort only works if fetch is still running [OK]
Common Mistakes:
  • Ignoring fetch completion timing
  • Assuming abort always cancels
  • Not handling errors but expecting cancel
5. You want to cancel a fetch request if it takes longer than 3 seconds. Which code snippet correctly implements this using AbortController?
hard
A. const controller = new AbortController(); setTimeout(() => controller.abort(), 3000); fetch(url);
B. const controller = new AbortController(); setTimeout(() => controller.abort(), 3000); fetch(url, { signal: controller.signal }) .catch(e => console.log(e.name));
C. const controller = new AbortController(); fetch(url); setTimeout(() => controller.abort(), 3000);
D. const controller = new AbortController(); fetch(url, { signal: controller }); setTimeout(() => controller.abort(), 3000);

Solution

  1. Step 1: Setup AbortController and timeout before fetch

    Create controller, then set a timeout to call abort after 3 seconds.
  2. Step 2: Pass controller.signal to fetch and handle errors

    Pass signal option to fetch and catch abort errors to avoid unhandled exceptions.
  3. Final Answer:

    const controller = new AbortController(); setTimeout(() => controller.abort(), 3000); fetch(url, { signal: controller.signal }) .catch(e => console.log(e.name)); -> Option B
  4. Quick Check:

    Timeout abort + signal + catch = D [OK]
Hint: Set timeout before fetch and pass signal with catch [OK]
Common Mistakes:
  • Calling abort without passing signal to fetch
  • Not catching abort errors
  • Calling abort after fetch without signal
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