Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React native How to fetch from api every x minutes

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

like image 541
MePo Avatar asked Dec 20 '16 09:12

MePo


People also ask

How do you call an API every minute for a dashboard in React?

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.

How do you call a function in every X seconds in React?

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() );


3 Answers

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];
};
like image 65
Jo Momma Avatar answered Oct 19 '22 05:10

Jo Momma


 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);
  });

}
like image 28
Shailesh Prajapati Avatar answered Oct 19 '22 06:10

Shailesh Prajapati


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

like image 4
Yusuf Khan Avatar answered Oct 19 '22 07:10

Yusuf Khan