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

JS创建新对象返回空值,calculateDistance执行后setState无法更新状态

问题解决方案

核心原因

你的代码无法拿到预期结果本质是异步时序问题:Leaflet 的 routesfound 是路由计算完成后才会触发的异步事件,你在 calculateDistance 中同步返回数组时,所有回调都还没执行,拿到的全是空对象。

其他隐藏问题

  • 每次调用 calculateDistance 都重新初始化地图实例,多次调用会抛出 DOM 已被占用的错误,地图实例只需在组件挂载时初始化一次即可。
  • 你用 Object.defineProperty 新增的属性默认是不可枚举的,JSON.stringify 序列化时会自动忽略,这就是你之前给原对象加属性、序列化后看不到变化的原因。

改造代码

1. 提前初始化地图

在组件挂载阶段完成地图初始化,存在实例属性上复用:

componentDidMount() {
  this.map = L.map('route-map').setView([52.237049, 21.017532], 11);
  // 其他地图初始化逻辑写在这里
}

2. 改造异步计算逻辑

把 calculateDistance 改造成返回 Promise,等所有路由计算完成后再返回结果:

calculateDistance(result) {
  // 用Promise.all等待所有异步路由计算完成
  return Promise.all(this.state.teams.map(team => {
    return new Promise((resolve) => {
      const routeControl = L.Routing.control({
        waypoints: [
          L.latLng(team.lat, team.long),
          L.latLng(result.y, result.x)
        ],
        show: true,
      }).addTo(this.map)

      routeControl.on('routesfound', e => {
        const dist = e.routes[0].summary.totalDistance;
        // 直接返回普通对象,需要保留原team属性直接展开即可
        resolve({
          ...team,
          id: team.id,
          distance: dist
        })
        // 移除用完的控件,避免地图上堆多余元素
        this.map.removeControl(routeControl)
      })
    })
  }))
}

3. 改造事件处理逻辑

等待异步计算完成后再更新 state:

async handleSearch(result) {
  const newTeams = await this.calculateDistance(result)
  this.setState({ teams: newTeams })
}

补充说明

如果你确实需要用 Object.defineProperty 定义不可写的属性,必须加上 enumerable: true 配置,否则序列化时会被忽略:

Object.defineProperty(newTeam, 'distance', {
  value: dist,
  writable: false,
  enumerable: true // 必加配置项
})

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 22:54:07