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

React setState更新数组状态时提示无法添加新属性报错

问题描述

在项目中接入Geolocation定位服务实现位置持续监听时,将每次回调返回的坐标推入预先声明的数组变量,调用setState更新坐标列表状态时抛出cannot add new property错误。
原有问题代码如下:

let dataarray = []
const startTrackingFunction = async () => {
  await Geolocation.watchPosition(
    position => {
      const crd = position.coords;

      setPosition({
        latitude: crd.latitude,
        longitude: crd.longitude,
        latitudeDelta: LATITUDE_DELTA,
        longitudeDelta: LONGITUDE_DELTA,
      });
      dataarray.push(crd);
      setCoordinates(dataarray);

    },
    error => {
      console.log(error);
    },
    {
      showLocationDialog: true,
      enableHighAccuracy: true,
      timeout: 20000,
      maximumAge: 0,
      distanceFilter: 0,
    });
  setTracking(true);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
错误原因
  • 违反React状态不可变原则:第一次调用setCoordinates(dataarray)后,React会对传入的状态值做冻结处理(Object.freeze),禁止任何修改操作。后续位置更新触发回调时,代码仍对同一个dataarray数组引用执行push操作,本质是给已冻结的数组对象新增索引属性,直接触发cannot add new property报错。
  • 接口误用:Geolocation.watchPosition不是Promise类型接口,添加await没有实际等待效果,该方法会同步返回位置监听器的唯一ID,用于后续取消监听。
  • 存储方式不合理:将坐标数组声明在组件外部的全局作用域,容易引发组件多实例数据污染、闭包取值异常等问题。
修复方案

移除外部全局数组变量,使用React状态的函数式更新做不可变数据修改,每次更新返回全新的数组引用,同时修正watchPosition的调用方式:

const startTrackingFunction = () => {
  // 同步获取监听器ID,用于后续停止定位时清除监听
  const watchId = Geolocation.watchPosition(
    position => {
      const crd = position.coords;

      setPosition({
        latitude: crd.latitude,
        longitude: crd.longitude,
        latitudeDelta: LATITUDE_DELTA,
        longitudeDelta: LONGITUDE_DELTA,
      });
      // 基于上一次的坐标状态生成新数组,不修改原状态值
      setCoordinates(prevCoords => [...prevCoords, crd]);
    },
    error => {
      console.log(error);
    },
    {
      showLocationDialog: true,
      enableHighAccuracy: true,
      timeout: 20000,
      maximumAge: 0,
      distanceFilter: 0,
    }
  );
  setTracking(true);
  // 可将watchId存入ref/state,页面卸载或停止定位时调用 Geolocation.clearWatch(watchId) 避免内存泄漏
}

注意事项

  • 所有React状态更新都要遵循不可变原则:数组更新使用展开运算符、map/filter/concat等返回新数组的方法,对象更新使用展开运算符、Object.assign创建新对象,禁止直接修改原状态引用。
  • 如果需要在组件内存储不触发重渲染的临时变量,使用useRef而非组件外的全局变量,避免闭包和多实例冲突问题。

内容的提问来源于stack exchange,提问作者jessanKhan7

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 04:27:16