Created
August 18, 2025 23:18
-
-
Save cNoveron/bd3871a980421a5a46e58e163e01f42c to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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