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.