3

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?

1
  • Please add the relevant code here, so that it can be solved even without using a third party service Commented Jul 31, 2019 at 18:09

1 Answer 1

2

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]); 
Sign up to request clarification or add additional context in comments.

3 Comments

My experiment shows that setResponse(null) and setError(null) is not called the second time.
@Elye Didn't get you.. can you elaborate?
I call useFetch(myUrl, option) once, and it works. The second time it is called, it doesn't work anymore, and just get back the same result. Did I use hooks wrongly?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.