Skip to content

Instantly share code, notes, and snippets.

@cNoveron
Created August 18, 2025 23:18
Show Gist options
  • Select an option

  • Save cNoveron/bd3871a980421a5a46e58e163e01f42c to your computer and use it in GitHub Desktop.

Select an option

Save cNoveron/bd3871a980421a5a46e58e163e01f42c to your computer and use it in GitHub Desktop.
import React, { useState, useEffect, useRef } from "react";
import "./styles.css";
// AbortController is a built-in Web API - no import needed in modern browsers/Node.js
// For older environments, you might need a polyfill
function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState("");
useEffect(() => {
// Reset state when URL changes
setLoading(true);
setError("");
// Create AbortController for cleanup
const controller = new AbortController();
const fetchData = async () => {
try {
const response = await fetch(url, {
signal: controller.signal,
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const result = await response.json();
// Only update state if component is still mounted
if (!controller.signal.aborted) {
setData(result);
setLoading(false);
}
} catch (err) {
// Don't set error state if request was aborted (cleanup)
if (!controller.signal.aborted) {
setError(err.message);
setLoading(false);
}
}
};
fetchData();
// Cleanup function to cancel request if component unmounts
// or URL changes before request completes
return () => {
controller.abort();
};
}, [url]); // Re-run effect when URL changes
return { data, loading, error };
}
export default function App() {
const postIds = [1, 2, 3, 4, 5, 6, 7, 8];
const [index, setIndex] = useState(0);
const {
loading,
data: post,
error,
} = useFetch(`https://jsonplaceholder.typicode.com/posts/${postIds[index]}`);
const incrementIndex = () => {
setIndex((i) => (i === postIds.length - 1 ? i : i + 1));
};
if (loading === true) {
return <p>Loading</p>;
}
if (error) {
return (
<>
<p>{error}</p>
<button onClick={incrementIndex}>Next Post</button>
</>
);
}
return (
<div className="App">
<h1>{post.title}</h1>
<p>{post.body}</p>
{error && <p>{error}</p>}
{index === postIds.length - 1 ? (
<p>No more posts existss ....</p>
) : (
<button onClick={incrementIndex}>Next Post</button>
)}
</div>
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment