I'm fetching API with useEffect and API responding correct like
{response: {message: "This is a image link", status: "success"}, error: null}
Second time when I'm receiving next API call response and If there is a error then old response is not removing. It's showing like this
{response: {message: "This is a image link", status: "success"}, error: TypeError}
I worked this tutorial code for fetching API
Check my exact code in codesandbox
import React, { useState } from "react";
import ReactDOM from "react-dom";
import "./styles.css";
const useFetch = (url, options) => {
console.log("useFetch");
const [response, setResponse] = React.useState(null);
const [error, setError] = React.useState(null);
React.useEffect(() => {
const FetchData = async () => {
try {
const res = await fetch(url, options);
const json = await res.json();
setResponse(json);
// console.log("json - ", json);
} catch (error) {
// console.log("error - ", error);
setError(error);
}
};
FetchData();
}, [url]);
return { response, error };
};
function App() {
const API_URL = `https://dog.ceo/api/breeds/image/random`;
const [apiUrl, setApiUrl] = useState(API_URL);
const res = useFetch(apiUrl, {});
console.log("res - ", res);
if (!res.response) {
return <div>Loading...</div>;
}
const apiCallAgain = () => {
const apiUrl = `https://d.ceo/api/breeds/image/q`;
setApiUrl(apiUrl);
};
const dogName = res.response.status;
const imageUrl = res.response.message;
return (
<div className="App">
<div>
<button onClick={apiCallAgain}>API Call</button>
<h3>{dogName}</h3>
<div>
<img src={imageUrl} alt="avatar" />
</div>
</div>
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
open console and check res
object by default. Now click on API Call
button and check res
object again. When I'm using useState null
in starting then why old state is showing?
When a component rerenders, hooks do not reinitialize all state in them. State cannot not work if that were the case (component re-renders when you change state).
Instead for each render, useState
hook stores and returns it's specific value for that render. In your case when the API_URL
changes, useEffect
reruns, but the state variables don't.
From the docs:
This is a way to “preserve” some values between the function calls — useState is a new way to use the exact same capabilities that this.state provides in a class. Normally, variables “disappear” when the function exits but state variables are preserved by React.
A fix for this would be to reset the state for response and error in useEffect
:
React.useEffect(() => {
setResponse(null);
setError(null);
const FetchData = async () => {
try {
const res = await fetch(url, options);
const json = await res.json();
setResponse(json);
// console.log("json - ", json);
} catch (error) {
// console.log("error - ", error);
setError(error);
}
};
FetchData();
}, [url]);