I'm writing a function in Javascript that makes a fetch and receives results that are paginated (as expected, the results are long).
The results will contain a "next_page" which is the fetch home url for the next page of results.Ideally I would like to loop and constantly fetch until I reach the end of the results aka when "next_page" = null.
I can't seem to figure out how to loop through the results while next_page isn't null. What seems to happen is I get stuck in an infinite while loop.
Any suggestions welcome. I've provided pseudo code below.
while(next_page!=null){
fetch(apiUrl)
.then(res=>res.json())
.then(data => {
apiUrl=data["next_page]
}
if(apiUrl == null)
{
res.send(data)
break;
}
}
I was thinking the while loop would let me iterate until there was no next_page (aka when it's null). Seems like it's just infinite looping without ever hitting the fetch because the apiUrl doesn't get set to null.
You can try below function, instead of while loop
// Initial API Call
fetchData('http://localhost/test1.php?page=1');
// Create the function for API Call
function fetchData(apiUrl){
fetch(apiUrl)
.then(res=>res.json())
.then(data => {
console.log(data);
apiUrl = data['next_page'];
// Check next API url is empty or not, if not empty call the above function
if(apiUrl != '' && apiUrl != null){
fetchData(apiUrl);
}
})
}
This is probably because you're reading data["next_page"] to apiUrl, but then checking a different variable in the loop. Should be while(apiUrl) { ... instead.
Related
I'm new around here and I'm studying JS! In particular JSON! However, I have come across an exercise that I cannot solve, also because I do not understand what I am doing wrong. I need to extract the information about the planets from the StarWars API. So I do the classic fetch and as a result I get the generic information about the planet in the form of a JSON.
However, I have to extract the planet name and I get stuck, because when I check the PlanetsData variable, it gives me undefined. Ergo the cycle I wrote to extract the names of the planets doesn't work for some reason.
So, my question is:
Why do I get "undefined" for the PlanetsData variable? .. Shouldn't I get the JSON, which displays correctly in the console?
Did I write the cycle correctly?
Thanks to who will answer me!
This is my code:
async function getPlanetsData() {
const planetsData = await fetch ("https://swapi.dev/api/planets").then(data => {
return data.json()}).then(planets => {console.log(planets.results)}) // ---> Here i receive the JSON data
for (let key in planetsData) {
const someInfo = planetsData.results[key].name
console.log(JSON.stringify(someInfo)) } // ---> I don't understand why, but I don't get anything here. There is no response in the console, as if the call did not exist
}
getPlanetsData()
You can write the same function in a different and clearer way,
check the comments to understand the code!
async function getPlanetsData() {
// 1. Fetch and wait for the response
const response = await fetch ("https://swapi.dev/api/planets");
// 2. Handle the response, in that case we return a JSON
// the variable planetsData now have the whole response
const planetsData = await response.json();
// console.log(planetsData); // this will print the whole object
// 3. Return the actual data to the callback
return planetsData;
}
// Function usage
// 4. Call "getPlantesData" function, when it completes we can call ".then()" handler with the "planetsData" that contains your information
getPlanetsData().then(planetsData => {
// 5. Do whatever you want with your JSON object
// in that case I choose to print every planet name
var results = planetsData.results; // result array of the object
results.forEach(result => console.log(result.name));
});
It seems that you have the same issue as : read and save file content into a global variable
Tell us if it does solve your issue or not.
(UPDATE)
To answer explicitly to your questions.
First question:
To get value into variable planetsData you can do this:
async function getPlanetsData() {
const response = await fetch ("https://swapi.dev/api/planets")
const planetsData = await response.json()
for (let key in planetsData) {
const someInfo = planetsData.results[key].name
console.log(JSON.stringify(someInfo))
}
}
getPlanetsData()
Second question:
You didn't write the cycle correctly.
To resolve promises it is preferable to choose between using await and.
I'm making a currency convert app that is using an API. When I fetch to the API the data variable has the JSON that I need. But when I store it to a the global variable, and console.log that, the output is null.
CODE:
const API_URL = 'SECRET';
let currency_json = null;
//Makes the request
async function getJSONdata(url) {
loading.style.display = '';
fetch(url)
.then(res => res.json())
.then(data => {
console.log(data); //Outputs the JSON. For some reason it gives null
currency_json = data;
})
.catch(err => console.log(err))
loading.style.display = 'none';
}
//Calls the function
getJSONdata(API_URL);
console.log(currency_json); //Outputs null
Also it doesn't give any errors. And I have read another person's solution on another website (To add Timeout somewhere), problem is they didn't said where or how to put it.
You're making an async call. Fetch gets data, but it is not available right away.
You need to wait for data to be available. Inside then you wait for it to be available and that's why it's working.
You could use async/async, but it seems you're making the call at a module level and that's not available there. You should move your code to execute from inside the promise callback (then method).
What you've heard about setTimeout is a form of long polling, you could implement it something like this
const longPollCallback = () => {
if (currency_json) {
console.log(currency_json)
} else {
setTimeout(longPollCallback, 500)
}
}
setTimeout(longPollCallback, 500)
But you should rely on then, async/await instead of long polling.
$.getJSON(url, function(json) {
for (var i in json) {
if (json[i].emaill == userMail) {
role = data[i].role
}
}
return role
});
i need to pass role variable to the another function
$.getJSON(
url,
[data],
[callback] //Do what u want
)
Process the role in callback
Regardless of where you want the data, you first need to understand how javascript handles asynchronous code (and what that means for YOU, the developer) Because $.getJSON is asynchronous, doing something like return role will not do anything useful in your regular idea of how functions return values. Something introduced recently is await/async which attempts to abstract away a lot of this code. However, this also comes with some caveats. What I would do is use async/await to make things a lot more simple. I would use fetch:
async function getUserRole (userEmail) {
const response = await fetch(url);
const json = await response.json();
let role;
json.forEach(user => {
if(user.email === userEmail) {
role = user.role;
}
}
return role;
}
Because of the await keyword before the fetch and response.json() the javascript engine will not move onto the next line even though these are asynchronous calls. This makes the code behave more like you would expect. Then after we get the json data, we can iterate over each element with the array function forEach and set the role based on the passed in userEmail. Do note however, that you see the async declaration before the function? That is required anytime you use await. This means that you will also need to decorate the function that is calling getUserRole with async as well.
I originally had only one URL to fetch data, and my app worked flawlessly. But then I realized I had to use two different URLs to fetch the data I needed. So I changed the code a little bit. Everything is pretty much the same except for the getData function, where I used map to iterate the list of URLs and fetch the data. My app is really buggy now.
Problems:
When I search for a streamer, it sometimes never renders the result on the page. And the message "search for your favorite streamer!" doesn't disappear even though this.state.value is now NOT equal to ' '. But when I change the input, it gets rendered out of nowhere.
It sometimes fails to render the data fetched and I get the FinderResultContainer rendered with no data in it. (No name, no img, no offline/online.)
What is exactly happening here? I feel like it is because I am not using the component life cycle methods. If so, then what exactly do I need to do? I am a total beginner, so I need to some guidance.
getData(value) {
let streamerData = [];
let streamerInfo = {};
let urls = ['https://wind-bow.gomix.me/twitch-api/streams/' + value, 'https://wind-bow.gomix.me/twitch-api/users/' + value];
urls.map(function(each, index) {
fetch(each).then((response) =>
response.json()
).then((streamer) => streamerData.push(streamer)).then(()=>streamerInfo[index]=streamerData[index]).then(()=>{if (index === urls.length-1){this.setState({streamer: streamerData})}})},this)
}
https://codepen.io/brood915/pen/OWQpmy
fetch is asynchronous and returns a promise, so you don't know exactly when it'll be done. You can use Promise.all() to wait every promise to resolve and then work with the data (note that all promises will execute at the same time, so if you have a large list of urls you will be sending tons of request per second).
Edit: I saw your pen and simplified the code, this works fine to me.
No blank component here. Note that you only need to use then when returning promises.
getData(value, type) {
let urls = [
'https://wind-bow.gomix.me/twitch-api/streams/' + value,
'https://wind-bow.gomix.me/twitch-api/users/' + value
];
const getJson = url => fetch(url).then(res => res.json());
Promise.all(urls.map(getJson))
.then(streamer => {
if (type === "search") {
this.setState({ streamer });
console.log("searching")
} else {
console.log("displaying");
this.getStreamer(streamer[0], streamer[1]);
}
}).catch(err => {
console.log('Something went wrong...')
})
}
So I'm trying to fetch all 'places' given some location in React Native via the Google Places API. The problem is that after making the first call to the API, Google only returns 20 entries, and then returns a next_page_token, to be appended to the same API call url. So, I make another request to get the next 20 locations right after, but there is a small delay (1-3 seconds) until the token actually becomes valid, so my request errors.
I tried doing:
this.setTimeout(() => {this.setState({timePassed: true})}, 3000);
But it's completely ignored by the app...any suggestions?
Update
I do this in my componentWillMount function (after defining the variables of course), and call the setTimeout right after this line.
axios.get(baseUrl)
.then((response) => {
this.setState({places: response.data.results, nextPageToken: response.data.next_page_token });
});
What I understood is that you are trying to make a fetch based on the result of another fetch. So, your solution is to use a TimeOut to guess when the request will finish and then do another request, right ?
If yes, maybe this isn't the best solution to your problem. But the following code is how I do to use timeouts:
// Without "this"
setTimeout(someMethod,
2000
)
The approach I would take is to wait until the fetch finishes, then I would use the callback to the same fetch again with different parameters, in your case, the nextPageToken. I do this using the ES7 async & await syntax.
// Remember to add some stop condition on this recursive method.
async fetchData(nextPageToken){
try {
var result = await fetch(URL)
// Do whatever you want with this result, including getting the next token or updating the UI (via setting the State)
fetchData(result.nextPageToken)
} catch(e){
// Show an error message
}
}
If I misunderstood something or you have any questions, feel free to ask!
I hope it helps.
try this it worked for me:
async componentDidMount() {
const data = await this.performTimeConsumingTask();
if (data !== null) {
// alert('Moved to next Screen here');
this.props.navigator.push({
screen:"Project1.AuthScreen"})
}
}
performTimeConsumingTask = async() => {
return new Promise((resolve) =>
setTimeout(
() => { resolve('result') },
3000
)
);
}