I want to run fetch every x Minutes on android (using React native)
function getMoviesFromApiAsync() {
return fetch('https://facebook.github.io/react-native/movies.json').then((response) => response.json()) .then((responseJson) => {
return responseJson.movies; }) .catch((error) => { console.error(error); });
}
I went to use example from documentaion as i am not still sure how would i do this kind of fetch.
Im not sure on how should i even start this(Make a android native Handler maybe?). I only found a component but that is for ios iOS Background Fetch API Implementation
Using setInterval() We can pass an API call inside the setInterval() to make it run repeatedly. const res = await fetch(`https://jsonplaceholder.typicode.com/posts`); }, 2000); Once this interval is created, it will send the API request after every two seconds.
employ useEffect() hook to be called upon turning counter on/off or incrementing that; within useEffect() body you may call the function, incrementing count by one (if ticking is truthy, hence timer is on) with delayed execution (using setTimeout() );
I'm a little late to the party but I had to do something similar. I was making an API request to a server that fetches a bunch of locations, does some calculations and passes the data to a callback function in another part of the app to update a Map. I wanted this to run every "x" seconds. This is what I did:
I created a custom hook that I call from the map screen. I had two states I wanted to return (businessLocations, error). I created a timer at the top of the file that looks like this:
const [render, setRender] = useState(false);
useEffect(() => {
setTimeout(() => {
setRender(!render);
}, 20000);
}, [isScreenFocused, render]);
This was recreated every time the screen was focused or the render state changed. As you can see I trigger the render state to change every time 20 seconds is up causing the timer to re-start.
Below the useEffect
call I created a second useEffect
call that looks like this:
const fetching = useRef(false);
useEffect(() => {
const searchForLocations = async () => {
fetching.current = true;
await requestAllLocations()
.then((locations) => {
const results = locations.map(loc => {
return createBusinessFromAPI(loc);
});
setBusinessLocations(results);
locationsCallback(results);
fetching.current = false;
}).catch((error) => {
fetching.current = false;
throw error;
});
};
if (!fetching.current) {
searchForLocations().catch(error => setError(error));
}
}, [isScreenFocused, render]);
As you can see here, I use the hook useRef
(which doesn't change from render to render) to determine if the last request is still processing. If it is, I don't call searchForLocations()
on this render cycle and simply wait for the next one. You can also see that this entire useEffect
call is triggered when the timer is up because I use the render state as a dependency here too.
It may not be a perfect solution. I'm currently trying to refine it a little. But, it has worked for me so far.
Here is the entire file:
import React, {useEffect, useRef, useState} from 'react';
import {requestAllLocations} from '../api/requests';
import {createBusinessFromAPI} from '../model/BusinessCreator';
export default (isScreenFocused, locationsCallback) => {
const [businessLocations, setBusinessLocations] = useState([]);
const [error, setError] = useState(null);
const [render, setRender] = useState(false);
const fetching = useRef(false);
useEffect(() => {
setTimeout(() => {
setRender(!render);
}, 20000);
}, [isScreenFocused, render]);
useEffect(() => {
const searchForLocations = async () => {
fetching.current = true;
await requestAllLocations()
.then((locations) => {
const results = locations.map(loc => {
return createBusinessFromAPI(loc);
});
setBusinessLocations(results);
locationsCallback(results);
fetching.current = false;
}).catch((error) => {
fetching.current = false;
throw error;
});
};
if (!fetching.current) {
searchForLocations().catch(error => setError(error));
}
}, [isScreenFocused, render]);
return [businessLocations, error];
};
componentDidMount(){
this.timer = setInterval(()=> this.getMovies(), 1000)
}
async getMovies(){
fetch('https://facebook.github.io/react-native/movies.json', {method: "GET"})
.then((response) => response.json())
.then((responseData) =>
{
//set your data here
console.log(responseData);
})
.catch((error) => {
console.error(error);
});
}
If you want run your service in background then there is only one option you have that is headless js https://facebook.github.io/react-native/docs/headless-js-android.html or npm based on headless js like https://github.com/jamesisaac/react-native-background-task
headless base service can have minimum periodic frequency 15 not less than that
if need to run service lesser than that eg 5 minutes then you can use combination of headless js and setinterval like
BackgroundTask.define(async () => { //headless based runs every 15 minute
console.log('headless js service start')
this._interval = setInterval(() => {
console.log('setinterval for 5 minute start')
// Your code
}, 300000);
BackgroundTask.finish()
})
then inside your any component method like componentwillmount you need to schedule background task like
componentDidMount() {
BackgroundTask.schedule({
period: 900, // Aim to run every 15mins
})
}
you can use setinterval alone without headless JS but will be stop by android to save battery/resource
Note : to test these things you have to use real device as physical device go in doze mode or do things like stop background app to save battery/resource unlike emulators
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With