You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Native定位数组推送报错:TypeError无法添加新属性

React Native 位置追踪数组Push报错排查与修复

问题概述

开发React Native应用用于追踪用户位置并将坐标存入数组绘制路线时,执行push操作触发错误:

TypeError: cannot add a new property, js engine: hermes

该功能此前正常,尝试三种实现方式(CASE1、CASE2、CASE3)均无效,偶现无报错但数组始终为空的情况,仅单独页面的CASE4可正常运行。


各实现方案问题分析

CASE 1:组件内普通变量存储

import React, {useEffect} from 'react';
import {Alert, StyleSheet, TouchableOpacity, View} from 'react-native';
import Geolocation from 'react-native-geolocation-service';
import {moderateScale} from 'react-native-size-matters';
import Entypo from 'react-native-vector-icons/Entypo';
import {MainRoutes} from '../constants/Routes';
import colors from '../constants/theme';
const GpsTrackerScreen = ({navigation}) => {
  let location_route = [];
  useEffect(() => {
    watchPosition();
  }, []);

  const watchPosition = () => {
    try {
      const watchID = Geolocation.watchPosition(
        position => {
          let coords = {
            latitude: position.coords.latitude,
            longitude: position.coords.longitude,
          };

          location_route.push(coords);
        },
        error => Alert.alert('WatchPosition Error', JSON.stringify(error)),
      );
    } catch (error) {
      Alert.alert('WatchPosition Error', JSON.stringify(error));
    }
  };

  return (
    <View style={styles.container}>
      <TouchableOpacity
        onPress={() => navigation.navigate(MainRoutes.TrackHistoryScreen)}
        style={styles.HistoryButton}>
        <Entypo name={'back-in-time'} color={'#fff'} size={moderateScale(30)} />
      </TouchableOpacity>
    </View>
  );
};

export default GpsTrackerScreen;

const styles = StyleSheet.create({
  container: {flex: 1, backgroundColor: colors.white, alignItems: 'center'},
  HistoryButton: {
    width: moderateScale(50),
    position: 'absolute',
    top: 20,
    right: 20,
    zIndex: 200,
    alignSelf: 'center',
    height: moderateScale(50),
    justifyContent: 'center',
    paddingHorizontal: moderateScale(10),
    alignItems: 'center',
    elevation: 5,
    borderRadius: moderateScale(50),
    backgroundColor: colors.primaryColor,
  },
});

问题:location_route是组件内普通变量,组件重渲染时会被重置为空数组。同时Hermes引擎可能将这类变量优化为不可变对象,导致无法执行push操作。


CASE 2:useState存储但存在闭包问题

import React, {useEffect, useState} from 'react';
import {Alert, StyleSheet, TouchableOpacity, View} from 'react-native';
import Geolocation from 'react-native-geolocation-service';
import {moderateScale} from 'react-native-size-matters';
import Entypo from 'react-native-vector-icons/Entypo';
import fonts from '../constants/fonts';
import {MainRoutes} from '../constants/Routes';
import {SCREEN_WIDTH} from '../constants/scaling';
import colors from '../constants/theme';
const GpsTrackerScreen = ({navigation}) => {
  const [location_route, setLocationRoute] = useState([]);
  useEffect(() => {
    watchPosition();
  }, []);

  const watchPosition = () => {
    try {
      const watchID = Geolocation.watchPosition(
        position => {
          let coords = {
            latitude: position.coords.latitude,
            longitude: position.coords.longitude,
          };

          let temp_route = [...location_route];
          temp_route.push(coords);

          setLocationRoute(temp_route);
        },
        error => Alert.alert('WatchPosition Error', JSON.stringify(error)),
      );
    } catch (error) {
      Alert.alert('WatchPosition Error', JSON.stringify(error));
    }
  };

  return (
    <View style={styles.container}>
      <TouchableOpacity
        onPress={() => navigation.navigate(MainRoutes.TrackHistoryScreen)}
        style={styles.HistoryButton}>
        <Entypo name={'back-in-time'} color={'#fff'} size={moderateScale(30)} />
      </TouchableOpacity>
    </View>
  );
};

export default GpsTrackerScreen;

const styles = StyleSheet.create({
  container: {flex: 1, backgroundColor: colors.white, alignItems: 'center'},
  HistoryButton: {
    width: moderateScale(50),
    position: 'absolute',
    top: 20,
    right: 20,
    zIndex: 200,
    alignSelf: 'center',
    height: moderateScale(50),
    justifyContent: 'center',
    paddingHorizontal: moderateScale(10),
    alignItems: 'center',
    elevation: 5,
    borderRadius: moderateScale(50),
    backgroundColor: colors.primaryColor,
  },
});

问题:useEffect依赖数组为空,watchPosition内引用的location_route始终是初始空数组,每次更新都会基于空数组添加新坐标,导致数组仅保留最后一个值,且闭包问题导致无法获取最新状态。


CASE 3:全局变量存储

import React, {useEffect} from 'react';
import {Alert, StyleSheet, TouchableOpacity, View} from 'react-native';
import Geolocation from 'react-native-geolocation-service';
import {moderateScale} from 'react-native-size-matters';
import Entypo from 'react-native-vector-icons/Entypo';
import {MainRoutes} from '../constants/Routes';
import colors from '../constants/theme';

let location_route = [];
const GpsTrackerScreen = ({navigation}) => {
  useEffect(() => {
    watchPosition();
  }, []);

  const watchPosition = () => {
    try {
      const watchID = Geolocation.watchPosition(
        position => {
          let coords = {
            latitude: position.coords.latitude,
            longitude: position.coords.longitude,
          };

          location_route.push(coords);
        },
        error => Alert.alert('WatchPosition Error', JSON.stringify(error)),
      );
    } catch (error) {
      Alert.alert('WatchPosition Error', JSON.stringify(error));
    }
  };

  return (
    <View style={styles.container}>
      <TouchableOpacity
        onPress={() => navigation.navigate(MainRoutes.TrackHistoryScreen)}
        style={styles.HistoryButton}>
        <Entypo name={'back-in-time'} color={'#fff'} size={moderateScale(30)} />
      </TouchableOpacity>
    </View>
  );
};

export default GpsTrackerScreen;

const styles = StyleSheet.create({
  container: {flex: 1, backgroundColor: colors.white, alignItems: 'center'},
  HistoryButton: {
    width: moderateScale(50),
    position: 'absolute',
    top: 20,
    right: 20,
    zIndex: 200,
    alignSelf: 'center',
    height: moderateScale(50),
    justifyContent: 'center',
    paddingHorizontal: moderateScale(10),
    alignItems: 'center',
    elevation: 5,
    borderRadius: moderateScale(50),
    backgroundColor: colors.primaryColor,
  },
});

问题:全局变量不会随组件卸载重置,易引发内存泄漏;组件多次挂载时会重复向同一数组添加坐标。此外Hermes严格模式下,全局对象属性可能被标记为不可扩展,导致push失败。


CASE 4:组件内变量+手动触发

import React, {useEffect, useState} from 'react';
import {Alert, StyleSheet, TouchableOpacity, View} from 'react-native';
import Geolocation from 'react-native-geolocation-service';
import {moderateScale} from 'react-native-size-matters';
import SplashScreen from 'react-native-splash-screen';
import Entypo from 'react-native-vector-icons/Entypo';
const GpsTrackerScreen = ({navigation}) => {
  let location_route = [];
  const [watchid, setWatchId] = useState(null);
  SplashScreen.hide();
  const clearwatch = () => {
    Geolocation.clearWatch(watchid);
  };
  const watchPosition = () => {
    try {
      const watchID = Geolocation.watchPosition(
        position => {
          let coords = {
            latitude: position.coords.latitude,
            longitude: position.coords.longitude,
          };

          location_route.push(coords);
          console.log(location_route, 'location_route');
        },
        error => Alert.alert('WatchPosition Error', JSON.stringify(error)),
        {
          accuracy: {
            android: 'high',
            ios: 'best',
          },
          enableHighAccuracy: false,
          timeout: 15000,
          maximumAge: 10000,
          distanceFilter: 0,
          forceRequestLocation: true,
          forceLocationManager: true,
          showLocationDialog: true,
        },
      );
      setWatchId(watchID);
    } catch (error) {
      Alert.alert('WatchPosition Error', JSON.stringify(error));
    }
  };

  return (
    <View style={styles.container}>
      <TouchableOpacity
        onPress={() => watchPosition()}
        style={styles.HistoryButton}>
        <Entypo name={'back-in-time'} color={'#fff'} size={moderateScale(30)} />
      </TouchableOpacity>
      <TouchableOpacity
        onPress={() => clearwatch()}
        style={styles.HistoryButton}>
        <Entypo name={'back-in-time'} color={'#fff'} size={moderateScale(30)} />
      </TouchableOpacity>
    </View>
  );
};

export default GpsTrackerScreen;

const styles = StyleSheet.create({
  container: {flex: 1, backgroundColor: '#fff', alignItems: 'center'},
  HistoryButton: {
    width: moderateScale(50),
    zIndex: 200,
    alignSelf: 'center',
    height: moderateScale(50),
    justifyContent: 'center',
    paddingHorizontal: moderateScale(10),
    alignItems: 'center',
    elevation: 5,
    margin: 100,
    borderRadius: moderateScale(50),
    backgroundColor: 'green',
  },
});

正常运行原因:location_route在watchPosition手动触发时创建,回调持有变量引用,且组件未因状态更新重渲染,变量不会被重置。但此方式无法响应数组变化更新UI,仅适合调试。


修复方案

方案1:useState函数式更新(推荐,支持UI更新)

import React, {useEffect, useState} from 'react';
import {Alert, StyleSheet, TouchableOpacity, View} from 'react-native';
import Geolocation from 'react-native-geolocation-service';
import {moderateScale} from 'react-native-size-matters';
import Entypo from 'react-native-vector-icons/Entypo';
import {MainRoutes} from '../constants/Routes';
import colors from '../constants/theme';

const GpsTrackerScreen = ({navigation}) => {
  const [location_route, setLocationRoute] = useState([]);
  let watchID = null;

  useEffect(() => {
    watchPosition();
    // 组件卸载时清除定位监听,防止内存泄漏
    return () => {
      if (watchID) Geolocation.clearWatch(watchID);
    };
  }, []);

  const watchPosition = () => {
    try {
      watchID = Geolocation.watchPosition(
        position => {
          const coords = {
            latitude: position.coords.latitude,
            longitude: position.coords.longitude,
          };
          // 函数式更新,确保基于最新数组状态添加坐标
          setLocationRoute(prevRoute => [...prevRoute, coords]);
        },
        error => Alert.alert('WatchPosition Error', JSON.stringify(error)),
        {
          accuracy: {android: 'high', ios: 'best'},
          enableHighAccuracy: false,
          timeout: 15000,
          maximumAge: 10000,
          distanceFilter: 0,
          forceRequestLocation: true,
          forceLocationManager: true,
          showLocationDialog: true,
        }
      );
    } catch (error) {
      Alert.alert('WatchPosition Error', JSON.stringify(error));
    }
  };

  return (
    <View style={styles.container}>
      <TouchableOpacity
        onPress={() => navigation.navigate(MainRoutes.TrackHistoryScreen)}
        style={styles.HistoryButton}>
        <Entypo name={'back-in-time'} color={'#fff'} size={moderateScale(30)} />
      </TouchableOpacity>
    </View>
  );
};

export default GpsTrackerScreen;

const styles = StyleSheet.create({
  container: {flex: 1, backgroundColor: colors.white, alignItems: 'center'},
  HistoryButton: {
    width: moderateScale(50),
    position: 'absolute',
    top: 20,
    right: 20,
    zIndex: 200,
    alignSelf: 'center',
    height: moderateScale(50),
    justifyContent: 'center',
    paddingHorizontal: moderateScale(10),
    alignItems: 'center',
    elevation: 5,
    borderRadius: moderateScale(50),
    backgroundColor: colors.primaryColor,
  },
});

核心改进:

  • 使用函数式更新setLocationRoute(prevRoute => [...prevRoute, coords]),避免闭包导致的状态过期问题
  • 添加组件卸载时的监听清理逻辑,防止内存泄漏
  • 配置完整的定位参数,确保定位回调稳定触发

方案2:useRef存储数组(无需UI更新时使用)

若仅需存储坐标、无需更新UI,可使用useRef,其.current属性不会随组件渲染重置:

import React, {useEffect, useRef} from 'react';
import {Alert, StyleSheet, TouchableOpacity, View} from 'react-native';
import Geolocation from 'react-native-geolocation-service';
import {moderateScale} from 'react-native-size-matters';
import Entypo from 'react-native-vector-icons/Entypo';
import {MainRoutes} from '../constants/Routes';
import colors from '../constants/theme';

const GpsTrackerScreen = ({navigation}) => {
  const location_route = useRef([]);
  let watchID = null;

  useEffect(() => {
    watchPosition();
    return () => {
      if (watchID) Geolocation.clearWatch(watchID);
    };
  }, []);

  const watchPosition = () => {
    try {
      watchID = Geolocation.watchPosition(
        position => {
          const coords = {
            latitude: position.coords.latitude,
            longitude: position.coords.longitude,
          };
          location_route.current.push(coords);
          // 通过location_route.current获取完整坐标数组
        },
        error => Alert.alert('WatchPosition Error', JSON.stringify(error)),
        {
          accuracy: {android: 'high', ios: 'best'},
          enableHighAccuracy: false,
          timeout: 15000,
          maximumAge: 10000,
          distanceFilter: 0,
          forceRequestLocation: true,
          forceLocationManager: true,
          showLocationDialog: true,
        }
      );
    } catch (error) {
      Alert.alert('WatchPosition Error', JSON.stringify(error));
    }
  };

  return (
    <View style={styles.container}>
      <TouchableOpacity
        onPress={() => navigation.navigate(MainRoutes.TrackHistoryScreen)}
        style={styles.HistoryButton}>
        <Entypo name={'back-in-time'} color={'#fff'} size={moderateScale(30)} />
      </TouchableOpacity>
    </View>
  );
};

export default GpsTrackerScreen;

const styles = StyleSheet.create({
  container: {flex: 1, backgroundColor: colors.white, alignItems: 'center'},
  HistoryButton: {
    width: moderateScale(50),
    position: 'absolute',
    top: 20,
    right: 20,
    zIndex: 200,
    alignSelf: 'center',
    height: moderateScale(50),
    justifyContent: 'center',
    paddingHorizontal: moderateScale(10),
    alignItems: 'center',
    elevation: 5,
    borderRadius: moderateScale(50),
    backgroundColor: colors.primaryColor,
  },
});

额外排查点

  1. 检查React Native与react-native-geolocation-service版本兼容性,近期版本可能对Hermes引擎做了调整
  2. 确认设备位置权限是否正常,权限拒绝会导致定位回调不触发,表现为数组为空
  3. 清除项目缓存:执行npm start --reset-cache或yarn start --reset-cache,缓存异常可能引发变量
相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 11:01:34