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

使用GoogleMap API展示自定义位置时,locations数组两处输出不一致求助

问题描述

我导入了一个名为data的JSON对象数组,数组中的对象包含address属性。我计划通过Google Map API查询address对应的坐标,生成名为locations的数组,以此创建自定义Marker。但通过console.log发现,useEffect内的fetchLocations函数与getCoordinates函数中,同一个locations变量的输出值却不相同。请问我哪里出现了错误?

import React, { useEffect, useState } from 'react'
import { GoogleMap, useLoadScript, InfoWindowF, MarkerF } from "@react-google-maps/api"
import { data } from './data'

const API_KEY = "1234567890"

export default function MyComponent() {

  const { isLoaded }: any = useLoadScript({
    googleMapsApiKey: API_KEY,
  })

  const result : any[] = [];
  const [locations, setLocations] = useState(result);

  useEffect(() => {
    const fetchLocations = async () => {
      const locations = await Promise.all(data.map(getCoordinates));
      console.log("Locations in fetchLocations", locations)
    };
    fetchLocations();
  }, []);


const getCoordinates = async (obj: any) => {
  const objData = await fetch("https://maps.googleapis.com/maps/api/geocode/json?address=" + obj.address + '&key=' + API_KEY)
  const response = await objData.json()
      const latitude = response.results[0].geometry.location.lat;
      const longitude = response.results[0].geometry.location.lng;
      const position = { 'lat': latitude, 'lng': longitude }
      locations.push(position)
      console.log("Locations in get Cooordinate", locations)
}


  if (!isLoaded) return <div>Loading...</div>
  return (
    <div className='flex flex-col'>
      <GoogleMap
        zoom={11}
        center={{ lat: 35.685661305110415, lng: 139.75255896834707 }}
        mapContainerClassName='w-full h-[32em] m-2 rounded-lg'
      >
        <>
          {locations.map(location=>{
            return(
              <>
                <MarkerF
                  position={{ lat: location.lat, lng: location.lng }}
                />
              </>
            )
          })
          }
        </>
      </GoogleMap>
      <button onClick={() => { setSelected(!selected) }}>Click</button>
    </div>
  )
}

错误分析与修复方案

核心问题

1. 变量作用域混乱

你同时存在三个互不关联的locations变量:

  • 组件状态的locations(通过useState声明)
  • fetchLocations里的局部变量locations(const locations = await Promise.all(...))
  • getCoordinates里操作的组件状态locations

这三个变量完全独立,自然日志输出不一样,而且fetchLocations里的locations因为getCoordinates没有返回值,最终是全undefined的数组。

2. 直接修改React状态

React状态是不可变的,直接调用locations.push(position)不会触发组件重新渲染,还会导致状态与UI不同步,异步操作下日志也会出现混乱。

3. Promise.all使用错误

Promise.all需要每个异步函数返回Promise结果,但你的getCoordinates没有返回值,所以最终得到的是一堆undefined。


修复后的代码

import React, { useEffect, useState } from 'react'
import { GoogleMap, useLoadScript, MarkerF } from "@react-google-maps/api"
import { data } from './data'

const API_KEY = "1234567890"

export default function MyComponent() {
  const { isLoaded } = useLoadScript({
    googleMapsApiKey: API_KEY,
  })

  // 直接初始化空数组作为状态
  const [locations, setLocations] = useState([]);
  // 补充原代码缺失的selected状态
  const [selected, setSelected] = useState(false);

  useEffect(() => {
    const fetchLocations = async () => {
      // 让getCoordinates返回坐标对象,Promise.all收集所有结果
      const fetchedLocations = await Promise.all(data.map(getCoordinates));
      // 过滤掉获取失败的null值
      const validLocations = fetchedLocations.filter(Boolean);
      // 用setLocations更新状态
      setLocations(validLocations);
      console.log("最终获取的坐标数组", validLocations)
    };
    fetchLocations();
  }, []);

  // 修改getCoordinates,专注于返回单个坐标,不直接操作状态
  const getCoordinates = async (obj) => {
    // 编码地址,避免特殊字符导致请求失败
    const encodedAddress = encodeURIComponent(obj.address);
    try {
      const objData = await fetch(`https://maps.googleapis.com/maps/api/geocode/json?address=${encodedAddress}&key=${API_KEY}`);
      const response = await objData.json();
      // 处理无结果的情况
      if (!response.results?.length) {
        console.error(`地址${obj.address}无法获取坐标`);
        return null;
      }
      const { lat, lng } = response.results[0].geometry.location;
      const position = { lat, lng };
      console.log(`地址${obj.address}对应的坐标`, position)
      return position;
    } catch (err) {
      console.error(`请求地址${obj.address}坐标失败`, err);
      return null;
    }
  }

  if (!isLoaded) return <div>Loading...</div>
  return (
    <div className='flex flex-col'>
      <GoogleMap
        zoom={11}
        center={{ lat: 35.685661305110415, lng: 139.75255896834707 }}
        mapContainerClassName='w-full h-[32em] m-2 rounded-lg'
      >
        {/* 列表渲染必须加key */}
        {locations.map((location, index) => (
          <MarkerF
            key={index}
            position={location}
          />
        ))}
      </GoogleMap>
      <button onClick={() => { setSelected(!selected) }}>Click</button>
    </div>
  )
}

关键修复点

  • 让getCoordinates返回单个坐标对象,不再直接操作状态,Promise.all就能正确收集所有结果。
  • 用setLocations统一更新状态,触发组件重新渲染,保证UI和状态同步。
  • 给地址做URL编码,避免特殊字符导致API请求失败。
  • 增加错误处理,防止地址无结果或请求失败时组件崩溃。
  • 补充原代码缺失的selected状态,修复按钮点击报错。
  • 给MarkerF添加key属性,符合React列表渲染规范。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 12:03:30