Why is my setStateAction not updating with json response data? - javascript

I am trying to fetch user data using the GitHub API, but when I make a request using fetch() the request is not sent until after the return(). The response data will only show after the page loads, but I need it before render to use as HTML parameters. I know it has something to do with JSON requests being asynchronous, but I'm not sure how to change the code to set the data properly.
const user = params.get("user");
const [userData, setUserData] = useState(null);
const [reqLimit, setReqLimit] = useState(null);
const getUserData = () => {
fetch(`https://api.github.com/users/${user}`)
.then(response => {response.json();})
.then(json => console.log(json))//'undefined'
.then(json => setUserData(json))
.catch(error => {
console.error('Error:', error);
});
};
useMemo(() => {
fetch(`https://api.github.com/rate_limit`)
.then(response => response.json())
.then(json => {
setReqLimit(json.resources.core);
if (json.resources.core.remaining < 1) {
console.error('Error:', 40
}
});
getUserData();
}, [userData]);
return (
<main>
//userData = null; (Why?)
</main>
)

fetch(`https://api.github.com/users/${user}`)
.then(response => response.json();) // return json
//.then(json => console.log(json))//'undefined' remove this from here
.then(json => setUserData(json))
.catch(error => {
console.error('Error:', error);
});

Related

trying to fetch data with fetch and promise, doesnt work (react)

Im trying to get data out of an API with fetch, i can console.log the result in the fetch but out of the fetch i cant reach the data.
So i got this fetchData.js file with the function in it:
export const fetchData = (url) => {
return fetch(url)
.then(response => response.json())
.then(result => console.log(result))
.catch(error => console.log('error', error))
}
and then in the app.jsx file i call the function like this:
import { fetchData } from "./fetchData";
const URL = "https://pokeapi.co/api/v2/pokemon"
function App() {
let data = fetchData(URL);
console.log(data);
//return etc
But the console.log(data) keeps saying "undefined"
Can somebody please help me ?
You have to wait for the asynchronous action to complete before logging it.
let data = fetchData(URL).then(() => {console.log(data);});
(also either remove then(result => console.log(result)) or return result from it)
fetchData is an async function, that is why the console.log is executed before fetchData is resolved:
export const fetchData = async (url) => {
return fetch(url)
.then(response => response.json())
.then(result => (result)) //--> data
.catch(error => console.log('error', error))
}
then in component, inside useEffect:
function App() {
const [data, setData] = useState([]) //--> keep data in component state
useEffect(()=> {
fetchData(URL) //--> fetch data when component is mounted
.then(response => setData(response))
}, []);
//...
}

Why is my JSON response returning undefined?

I'm trying to make a fetch request for COVID data in my React Native app but each time I try to inspect the response, the console outputs undefined for the json variable:
const [isLoading, setLoading] = useState(true);
const [data, setData] = useState({});
useEffect(() => {
fetch("https://api.covid19api.com/summary")
.then((response) => {
response.json();
})
.then((json) => {
console.log("json.. " + json);
setData(json);
})
.catch((error) => console.error(error))
.finally(() => setLoading(false));
}, []);
In the first .then(), you are not returning anything, so undefined is returned implicitly.
You should return the reponse.json():
.then((response) => {
return response.json();
})
Or shorter:
.then((response) => response.json())

What would this code look like if instead of "async/await" use "then and catch"?

There is such a method in a React application:
fetchData = async () => {
try {
const response = await fetch(`https://........`);
const data = (await response.json()).group;
this.setState({
data: data,
car: Object.keys(data)[0]
},this.filter);
} catch(err) {
console.log("404 Not Found");
}
};
How to write this part without async / await syntax, and using then and catch?
Just like this!
fetchData = () => {
fetch("YOUR_URL")
.then(response => response.json())
.then(json => json.group)
.then(data => {
this.setState({
data,
car: Object.keys(data)[0]
},this.filter);
})
.catch(err => {
console.log("404 Not Found");
});
}
It's simply-
fetchData = () => {
fetch(url)
.then(res => res.json())
.then(data => {
this.setState({data: data.group, car: Object.keys(data.group)[0]})
})
.catch(err => console.log(err));
};
If fetch returns a Promise you can:
fetchData = () => {
fetch(url)
.then(res => ... )
.catch(err => ...)
};
fetchData = () => {
return fetch(`https://........`)
.then(response => {
const data = response.json().group;
this.setState({
data: data,
car: Object.keys(data)[0]
},this.filter);
}).catch(err => {
console.log("404 Not Found");
});
};
response.json() won't return a Promise so you don't need await

Using RxJS and axios, how do you fetch data onClick in React component?

I'm struggling with how to fetch data using RxJS and axios onClick in a React component. But getting closer, I think. Any attempts I've tried either run when component mounts, not onClick, or don't run at all even onClick.
Basically, how to call onClick and how to pass a payload. There just seems to be nothing online to explain this which i would expect to be a common situation.
const MyComponent = () => {
const [data, setData] = useState(null);
const getData$ = new Subject(observer => {
axios
.post(`/my-url/`, **how to get payload to here**)
.then(response => {
observer.next(response.data);
observer.complete();
})
.catch(error => {
observer.error(error);
});
});
useEffect(() => {
const subs = getData$.subscribe({
next: res => setData(res),
});
return () => subs.unsubscribe();
}, []);
return (
<Button onClick={() => getData$.next(payload)} />
);
};
Any help appreciated.
you can pass in the payload in getData like this
const getData$ = (payload) => new Subject(observer => {
axios.post(`/my-url/`, payload)
.then(response => {
observer.next(response.data);
observer.complete();
})
.catch(error => {
observer.error(error);
});
});
This basically just creates an anonymous function called getData that returns your Subject. It's equivalent to this:
const getData$ = function (payload) {
return new Subject(observer => {
axios.post(`/my-url/`, payload)
.then(response => {
observer.next(response.data);
observer.complete();
})
.catch(error => {
observer.error(error);
});
});
};

React/FetchAPI: How to take data from related json by id

I want to take data from JSON, next take another data from related JSON by ID and push it to my state array movies.
This is my code:
state = {
movies: []
}
componentDidMount() {
fetch('https://api.themoviedb.org/3/movie/popular?api_key=APIKEY&page=1')
.then(response => response.json())
.then(data => {
const movies = data.results;
movies.forEach(movie => this.moviePageAndGenres(movie.id, movie));
this.setState({
movies
});
})
}
moviePageAndGenres = (id, element) => {
fetch('https://api.themoviedb.org/3/movie/' + id + '?api_key=APIKEY')
.then(response => response.json())
.then(data => {
element.genres = data.genres;
element.homepage = data.homepage;
});
}
In render() I just console.log my movies to check if data inside is correct.
Output:
image
So it's correct but when I check Component Props these props are not transferred.
image
This is how I transfer props:
const movies = this.state.movies.map(movie =>
<Movie genres={movie.genres}
homepage={movie.homepage}
key={movie.id}
title={movie.title}
poster={movie.poster_path}
rating={movie.vote_average}
/>
)
I guess it's problem with multiple call of asynchronousfetch(). But i don't know how to handle with it.
The reason its not working is, you are firing multiple fetch calls which are async and setting the state immediately after it. setState will get empty movies in that case.
fetch api returns a promise and you should set your state in promise resolution handler. Modify your componentDidMount like this.
componentDidMount() {
fetch('https://api.themoviedb.org/3/movie/popular?api_key=APIKEY&page=1')
.then(response => response.json())
.then(data => {
const movies = data.results;
Promise.all(movies.map(movie => fetch(
`https://api.themoviedb.org/3/movie/${movie.id}?api_key=APIKEY`
)))
.then(resp => Promise.all( resp.map(r => r.json()) ))
.then(result => {
const movies = result.map((data, i) => {
const movie = Object.assign(movies[i], {
genres: data.genres,
homepage: data.homepage
});
return movie;
});
this.setState({
movies
});
});
})
}
You need async await in this case and it’s good to use Promise.all because you are doing fetch in forEach.
For forEach you need await Promise.all and for fetch you need await. Which mean it will wait until the forEach is completed
Change
fetch('https://api.themoviedb.org/3/movie/popular?api_key=APIKEY&page=1')
.then(response => response.json())
.then(data => {
const movies = data.results;
movies.forEach(movie => this.moviePageAndGenres(movie.id, movie));
this.setState({
movies
});
})
To
fetch('https://api.themoviedb.org/3/movie/popular?api_key=APIKEY&page=1')
.then(response => response.json())
.then(async data => {
const movies = data.results;
await Promise.all(movies.forEach(async movie => await this.moviePageAndGenres(movie.id, movie)))
this.setState({
movies
});
})
Also
Change
moviePageAndGenres = (id, element) => {
fetch('https://api.themoviedb.org/3/movie/' + id + '?api_key=APIKEY')
.then(response => response.json())
.then(data => {
element.genres = data.genres;
element.homepage = data.homepage;
});
}
To
moviePageAndGenres = async (id, element) => {
return await fetch('https://api.themoviedb.org/3/movie/' + id + '?api_key=APIKEY')
.then(response => response.json())
.then(data => {
element.genres = data.genres;
element.homepage = data.homepage;
});
}

Categories