React native 如何每 x 分钟从 api 中获取

React native How to fetch from api every x minutes

我想 运行 在 android 上每 x 分钟获取一次(使用 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); }); 
}

我使用了 documentaion 中的示例,因为我仍然不确定我将如何进行这种提取。

我不确定我应该如何开始这个(也许制作一个 android 本机处理程序?)。我只找到了一个组件,但它适用于 ios iOS Background Fetch API Implementation

你必须在你收到回调的地方设置时间。

ComponentWillMount() {
    AsyncStorage.getItem('accessToken').then((token) => {
      this.setState({
        isLoading: false,
         time :5000

      });
    });
  },

您可以创建一个 AsyncTask(后台线程),它从您的 url 获取 json 并在定时器循环中调用它,如下所示:

异步任务:

private class FetchAPI extends AsyncTask<String, String, String> {

    BufferedReader reader;
    HttpURLConnection conn;

    @Override
    protected String doInBackground(String... params) {

        String data = null;
        try {
            // Defined URL  where to send data
            URL url = new URL(YOURURL);
            conn = (HttpURLConnection) url.openConnection();
            conn.connect();

            // Get the server response
            reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
            // conn.disconnect();


        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return null;
    }

     protected void onPostExecute(String result) {
        try {
            StringBuilder sb = new StringBuilder();
            String line = null;

            while((line = reader.readLine()) != null)
            {
                sb.append(line + "\n");
            }

            String serverResponse = sb.toString(); //Your JSON

        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}

您的计时段:

new Timer().schedule(new TimerTask() {
@Override
public void run() {
    // do your task here
    FetchAPI fetchAPI = new FetchAPI();
    fetchAPI.execute("");
}
}, 0, 5000);

此代码将调用 FetchAPI 方法,该方法使用后台线程从您的 URL 中获取 json。当您获得 JSON 后,您可以用它做任何您想做的事。该方法每 5 秒调用一次。根据您的需要编辑“5000”(以毫秒为单位的间隔)

我希望这可以帮助你 and/or 引导你朝着正确的方向前进

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

}

如果您希望运行您的服务在后台运行,那么您只有一个选择,那就是无头 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 可以有最小周期频率 15 不小于

如果需要 运行 服务少于 5 分钟,那么您可以使用无头 js 和 setinterval 的组合,例如

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

然后在你的任何组件方法中,比如 componentwillmount 你需要安排后台任务,比如

 componentDidMount() {
      BackgroundTask.schedule({
      period: 900, // Aim to run every 15mins 
      })
      }

您可以单独使用 setinterval 而不使用无头 JS,但会被 android 停止以节省 battery/resource

注意:要测试这些东西,您必须使用真实设备,因为物理设备进入打瞌睡模式或停止后台应用程序以保存 battery/resource 与模拟器不同

我参加派对有点晚了,但我不得不做类似的事情。我正在向服务器发出 API 请求,该服务器获取一堆位置,进行一些计算并将数据传递给应用程序另一部分的回调函数以更新地图。我希望每“x”秒运行。这就是我所做的:

我创建了一个从地图屏幕调用的自定义挂钩。我有两个想要 return 的州(businessLocations,错误)。我在文件顶部创建了一个计时器,如下所示:

const [render, setRender] = useState(false);
 
useEffect(() => {
   setTimeout(() => {
      setRender(!render);
   }, 20000);
}, [isScreenFocused, render]);

每次屏幕聚焦或渲染状态改变时都会重新创建。如您所见,我会在每次 20 秒后触发渲染状态更改,从而导致计时器重新启动。

useEffect 调用下方,我创建了第二个 useEffect 调用,如下所示:

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

正如您在此处看到的,我使用挂钩 useRef(在渲染与渲染之间不会发生变化)来确定最后一个请求是否仍在处理中。如果是,我不会在此渲染周期中调用 searchForLocations(),而只是等待下一个渲染周期。您还可以看到整个 useEffect 调用是在计时器启动时触发的,因为我在这里也将渲染状态用作依赖项。

这可能不是一个完美的解决方案。我目前正在尝试对其进行一些改进。但是,到目前为止它对我有用。

这是整个文件:

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