【问题标题】:Expo TaskManager - How do I pass a changed state to an outside function?Expo TaskManager - 如何将更改的状态传递给外部函数?
【发布时间】:2020-11-06 19:35:47
【问题描述】:

我正在使用react-nativeexpo 开发一个应用程序,我无法将状态更改传递给我的任务管理器,我想知道我哪里出错了。我不确定expo task manager 是否真的不能接受状态更改?基本上当我开始我的任务时,我检查传递的状态变量是真还是假,然后我想要改变状态。它工作一次,但任务管理器中的状态似乎保持不变,这意味着它一直试图签入我,因为它仍然将提交的变量视为错误:

***********APP.JS STATUS: true
"****LOCATION PINGING... submitted IS NOW:","false"

task.js

import * as TaskManager from 'expo-task-manager';
const TASK_FETCH_LOCATION_TEST = 'background-location-task';


export const configureBgTasks = ({ submitted, autoCheckin, autoCheckout }) => {
    
    TaskManager.defineTask(TASK_FETCH_LOCATION_TEST, ({ data, error }) => {

        if (error) {
            // Error occurred - check `error.message` for more details.
            return;
        }
        if (data) {
            //get location data from background
            const { locations } = data;
            console.log('****LOCATION PINGING... submitted IS NOW:', submitted);
            if (submitted === false) {
                autoCheckin();
                console.log('****CHECKING YOU IN...');
            } else if(submitted === true) {
                autoCheckout();
                console.log('*****CHECKING YOU OUT...')
            }
        }
    })
}

App.js

import React, { Component } from 'react';
import { StatusBar } from 'expo-status-bar';
import { StyleSheet, Text, View, Button, Platform, Alert } from 'react-native';
import * as Location from "expo-location";
import { configureBgTasks } from './task';
import * as TaskManager from 'expo-task-manager';
const TASK_FETCH_LOCATION_TEST = 'background-location-task';

class App extends Component {

  state = {
    submitted: false
  }


  async componentDidMount() {
    const { status } = await Location.requestPermissionsAsync();
    if (status === 'granted') {
      console.log('location permissions are granted...')
    }
  }
  
    stopBackgroundUpdate = async () => {
      Alert.alert('TRACKING IS STOPPED');
      //Location.stopLocationUpdatesAsync(TASK_FETCH_LOCATION_TEST)
  
      //UNREGISTER TASK
      //const TASK_FETCH_LOCATION_TEST = 'background-location-task_global';
      TaskManager.unregisterTaskAsync(TASK_FETCH_LOCATION_TEST);
    }


    //REFERENCES TO STATE
    autoTrackingCheckin = () => {
      console.log('^^firing checkin')
      this.setState({ submitted: true });
    }

    autoTrackingCheckout = () => {
      console.log('^^firing checkout')
      this.setState({ submitted: false });
    }
  

    executeBackground = async () => {

      //START LOCATION TRACKING
      const startBackgroundUpdate = async () => {
        Alert.alert('TRACKING IS STARTED');
    
        if(Platform.OS==='ios') {
    
          await Location.startLocationUpdatesAsync(TASK_FETCH_LOCATION_TEST, {
            accuracy: Location.Accuracy.BestForNavigation,
            //timeInterval: 1000,
            distanceInterval: 2, // minimum change (in meters) betweens updates
            //deferredUpdatesInterval: 1000, // minimum interval (in milliseconds) between updates
            // foregroundService is how you get the task to be updated as often as would be if the app was open
            foregroundService: {
              notificationTitle: 'Using your location for TESTING',
              notificationBody: 'To turn off, go back to the app and toggle tracking.',
            },
            pausesUpdatesAutomatically: false,
          });
    
        } else {
    
          await Location.startLocationUpdatesAsync(TASK_FETCH_LOCATION_TEST, {
            accuracy: Location.Accuracy.BestForNavigation,
            timeInterval: 1000,
            //distanceInterval: 1, // minimum change (in meters) betweens updates
            //deferredUpdatesInterval: 1000, // minimum interval (in milliseconds) between updates
            // foregroundService is how you get the task to be updated as often as would be if the app was open
            foregroundService: {
              notificationTitle: 'Using your location for TESTING',
              notificationBody: 'To turn off, go back to the app and toggle tracking.',
            },
            pausesUpdatesAutomatically: false,
          });
  
        }
      }



       //WHERE THE MAGIC IS SUPPOSED TO HAPPEN
        try {

          //REFERENCES FOR VARIABLES AND FUNCTIONS
          const submitted = this.state.submitted
          const autoCheckin = this.autoTrackingCheckin
          const autoCheckout = this.autoTrackingCheckout
          
          console.log('THE VARIABLE BEING PASSED...',submitted)
          configureBgTasks({ submitted, autoCheckin, autoCheckout })
          startBackgroundUpdate();
        }
        catch (error) {
          console.log(error)
        }


    }


  


  render() {

    console.log('***********APP.JS STATUS:', this.state.submitted);

    return (
      <View style={styles.container}>
      
      <Button
          onPress={this.executeBackground}
          title="START TRACKING"
        />
        
        <Button
          onPress={this.stopBackgroundUpdate}
          title="STOP TRACKING"
        />
      <StatusBar style="auto" />
      </View>
    );
  }
}

export default App;



const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'space-evenly',
  },
});

【问题讨论】:

    标签: javascript reactjs react-native expo background-process


    【解决方案1】:

    根据博览会的文档,所有任务都需要在 react-native 代码之外定义,在全局范围内:

    它必须在你的 JavaScript 包的全局范围内调用。特别是,它不能在任何 React 生命周期方法中调用,例如 componentDidMount。这个限制是因为当应用程序在后台启动时,我们需要启动你的 JavaScript 应用程序,运行你的任务然后关闭——在这种情况下没有安装任何视图。

    因此,我相信对您来说最好的解决方案是使用 Redux/Context 来实现状态行为 (as you can read here)

    【讨论】:

    • 由于问题显示了相关的工作代码,您至少应该添加最少量的相关和完整的 sn-p 来演示您指向的解决方案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-29
    • 1970-01-01
    • 2021-10-29
    • 1970-01-01
    • 2013-01-13
    相关资源
    最近更新 更多