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
)
);
}
Related
I have a problem with a simple function which where I want to call an API and then do something with the response. Basically, I just want to set my react component state to the response I get and then navigate to the other page The problem is that my code executes another part of the function before an API call is finished, and I end up on another page with console.log of undefined
There is my function:
const startNewGame = () => {
GameService.startGame()
.then((response) => {
setGame(response.data);
console.log(game);
navigate('intro');
})
.catch((e) => {
console.log(e);
});
};
I can wrap my navigate into if(!game !== undefined) but then I have to click two or more times on a button.
Thank you all guys for help :)
You probably do several things incorrect at the same time, so to understand what exactly is wrong might take some time. Take these steps to debug your code:
Make each .then call do only one thing (and stick to that principle in other cases). You could chain as many .then as you like. Moreover you could return data from one .then to the next, so your code might look like this:
GameService.startGame()
.then(response => response.data)
.then(data => {
setGame(data)
})
.then(() => {
console.log(game);
navigate('intro');
})
.catch((e) => {
console.log(e);
});
Understand your components composition. Where exactly are you saving your response? is it just local component useState or some Context Api state that wraps the app? When you navigate to "other page" your "current page" state will be unavailable to "other page" unless you keep the data somewhere up in the tree when both pages could access that.
For further references keep in mind that setGame is asynchronous, so you need to wait for the state to be updated to make sure that its updated.
Try this:
const startNewGame = () => {
GameService.startGame()
.then((response) => {
setGame(response.data);
// game is not updated yet
// console.log(game); <- Remove this line
// navigate('intro'); <- Remove this line
})
.catch((e) => {
console.log(e);
});
};
useEffect(()=>{
if(game !== undefined){
navigate('intro')
}
}, [game])
I'm currently doing some post requests within an interval function:
let getStatusIV = setInterval( () => {
let data = {
action: 'get_products_status',
import_id: importId
};
$.post( ajaxurl, data, function () {
} ).done( response => {
if (response.success && response.data) {
// showLoadingSpinner( '#wpcontent', response.data ); <- Sets the text at an overlay
}
} )
}, 500 );
This interval / post function returns the status of another AJAX call from my backend - for example: Processed 20 of 700 products
The problem is, that the requests are not resolving in the order they were called so as a result I'm getting this example:
Processed 20 of 700 products
Processed 19 of 700 products
Processed 30 of 700 products
Processed 80 of 700 products
Processed 75 of 700 products
Any idea to fix this? I really need short intervals so just settings a longer interval time dont helps.
That's how asynchronous programming works. Since you have so much things to be processed, keep calling .then() won't be that practical then. But why is the order so important? In reality most operations are processed asynchronously to maximize efficiency. I'm a newbee by the way, but I did encounter this, I just made everything asynchronous to solve the same problem.
------------------------------------
Okay, now I find a way to accomplish this. This is an example from JavaScript: The Definitive Guide by David Flanagan. You may want to check it out because it's indeed AWESOME.
function fetchSequentially(urls) {
const bodies = [];
//Response bodies are stored here
function fetchOne(url) {
return fetch(url)
.then((response) => response.text())
.then((body) => {
bodies.push(body);
});
}
let p = Promise.resolve(undefined);
//Fulfill an empty promise to initiate the promise chain
for (url of urls) {
p = p.then(() => fetchOne(url));
//Build the promise chain automatically
}
return p.then(() => bodies);
/*
Return bodies. It's a promise so you may call
.then() one last time to get the output.
For the progress bar, you may want to use event
to track how many requests have been done.
*/
}
Actually you can just use event to deal with the progress bar problem to keep the requests "parallel". Just emit an event to announce that one request has done. Listen to the event and track how many instead of which one has finished. Then the progress bar will never go backwards.
Hello I need to call a REST function with an ID, that returns a promise in React.js. This function will at some point contain a certain value in its response when called . Until another service has processed an initial request this value will be null.
This is what I have done so far:
while(myVariable){
myfunction(myID).then( (response) => {
if(response['value'] != null
myVariable = false;
}
});
}
The problem with this code is that the while loop is called as fast as possible and thus completely utilises the computer. So I need a function that allows me to poll for a result by an ID until the response of one of the function calls contains a valid response.
I have tried the following method but without success, because I don't have a fixed number of runs:
Wait promise inside for loop
Thanks in regards.
As you state, the problem is that the while loop runs eagerly, not waiting for each promise to resolve.
One way to solve that is to use recursion. Recursion gives you more control over when exactly you want to 'loop' next:
let getValue = () => {
myFunction(myID).then(response => {
if (response['value'] === null) {
setTimeout(getValue);
} else {
// here you know the other service has processed the initial request
}
});
};
First I wrapped the whole thing in a function called getValue. Note that this function is only called again after the promise resolves. (The call to setTimeout is a trick to use recursion without consuming the stack.) If this still runs too quickly, pass an additional parameter of 100 or so to the setTimeout invocation.
Alternatively, you may be able to use async/await similarly to the link you shared. I'm no expert on async/await but it should work the same with while loops as with for loops, judging by this and this.
You can use the async function with await.
I also use a delay function to delay each call to the myfunction().
While you get a response, you can break the while loop.
const delay = ms => new Promise((resolve, reject) => setTimeout(resolve, ms));
async function main() {
const myID = 1;
let response;
while (true) {
response = await myfunction(myID);
if (response["value"] != null) {
break;
}
await delay(5000);
}
//do Something once you get the response here below:
}
main();
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.
I send request to server everytime user types something. I use debounce for the 400ms delay:
type = debounce((text) => {
this.props.actions.loadInfo(text)
}, 400);
When I type something, stop and start again and repeat it, several requests are send and I receive irrelevant data. I use promises:
export const loadInfo = (text) => dispatch => {
loadData(text).then(result => {
dispatch(showUserData(result));
});
};
export const loadData = async (text) => {
const tabData = await axios.get(`url&query=${text}`);
return tabData;
}
I need somehow cancel previous request if user sends the new one(when he typed something), what is the best way to do that? I expected debounce will help me but not. I use axios. This is not duplicate of questions here, I checked provided solutions but thet don't help me
The problem is similar to this one. Axios cancellation API can be used to cancel old requests. This should be done in a function that does a request (loadData) and has direct access to Axios, it may be also debounced:
let cancelObj;
export const loadData = debounce((text) => {
if (cancelObj) {
this.cancelObj.cancel();
}
cancelObj = CancelToken.source();
return axios.get(`url&query=${text}`, {
cancelToken: this._fetchDataCancellation.token
}).catch(err => {
// request wasn't cancelled
if (!axios.isCancel(err))
throw err;
});
}, 200);
Since Redux is used, other solutions may involve it, they depend on how Redux is used.
Even I tried to use debounce function in my code but the problem is that if user types very fast stop and then again start typing, in that case, your input values get updated and UI get distorted, to avoid this I used XMLHttpRequest and its abort() to cancel the previous calls, if calls do not succeed then it will be canceled,
you can try this solution, https://stackoverflow.com/a/55509957/9980970