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

React中@react-google-maps/api地图标记不显示问题求助

问题排查与解决方案

核心问题

  1. 普通变量无法触发重渲染:当前markers是普通数组,异步生成坐标后push操作不会被React感知,导致Map组件接收的始终是初始空数组——只有修改Map组件代码触发热更新时,才会读取到已填充的数组。
  2. 异步逻辑时机错误:在组件渲染阶段直接调用异步的generateLatLng,不会等待所有坐标生成完成就渲染Map,且完成后无状态更新触发重渲染。
  3. useState误用导致无限重渲染:之前直接在循环中调用setMarkers,每次状态更新都会触发组件重渲染,进而再次执行循环,陷入死循环。

修复方案

  • 用useState存储markers状态,确保状态更新能触发组件重渲染。
  • 用useEffect监听properties和isLoaded的变化,仅当数据和地图API都准备好时,批量处理坐标生成。
  • 使用Promise.all等待所有坐标异步请求完成后,一次性更新markers,避免多次状态更新导致的不必要重渲染。

修改后的PropertyPage代码

import React, { useState, useEffect } from 'react'
import PropertyCard from './PropertyCard'
import RingLoader from 'react-spinners/RingLoader';
import Map from './Map';
import { Grid, Button, Image } from 'semantic-ui-react'
import { Link } from 'react-router-dom';
import { useLoadScript } from '@react-google-maps/api'
import { getGeocode, getLatLng } from 'use-places-autocomplete';
import { useGetPropertiesQuery } from '../../app/services/propertiesAPI'

const libraries = ['places']

const PropertyPage = () => {
    const { data: properties = [], isLoading, isError, error, isSuccess } = useGetPropertiesQuery()
    const { isLoaded } = useLoadScript({
        googleMapsApiKey: process.env.REACT_APP_GOOGLEMAPS_KEY,
        libraries,
    });
    const [markers, setMarkers] = useState([]);
    
    if (!isLoaded) {
        return <div>Map is loading...</div>
    }

    let content

    const generateLatLng = async (address) => {
        try {
            const results = await getGeocode({ address });
            if (results.length === 0) {
             return null;
            }
            const { lat, lng } = await getLatLng(results[0]);
            return lat && lng ? { lat, lng } : null;
        } catch (error) {
            console.error('Error while generating lat and lng:', error);
            return null;
        }
    };

    // 批量生成坐标并更新markers
    useEffect(() => {
        const fetchMarkers = async () => {
            if (!isSuccess || properties.length === 0) return;
            
            // 并行请求所有坐标
            const markerPromises = properties.map(property => generateLatLng(property.address));
            const results = await Promise.all(markerPromises);
            // 过滤掉无效结果
            const validMarkers = results.filter(marker => marker !== null);
            setMarkers(validMarkers);
        };

        fetchMarkers();
    }, [isSuccess, properties]); // 仅当数据就绪或属性列表变化时执行

    if (isLoading) {
        content = <h1>Loading...</h1>
    } else if (isError) {
        content = <div>{error.toString()}</div>
    } 

    if (isSuccess && properties.length > 0) {
            content = properties.map((property) => <PropertyCard key={property.id} property={property}/>)
    }
    

    const noPropertiesYetMessage = (
        <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
            <h1>You have no properties yet.</h1>
            <Button as={Link} to='/properties/add-new'>
                Add More
            </Button>
        <br></br>
        <div style={{ width: '50rem', height: '30rem', position: 'relative', overflow: 'hidden' }}>
            <Image fluid style={{ width: '100%', height: '100%', objectFit: 'cover' }} src='https://www.bhg.com/thmb/TXKtfIyA_UUCOWtMsLXetN5Wvb8=/1493x0/filters:no_upscale():strip_icc()/gray-exterior-white-trim-path-09767f9e-83bad323e9d2473b90e69add9165c12f.jpg' alt='building entrance'/>
        </div>
        </div>
    )

    return (
        <div>
            <RingLoader color={'#F5A623'} loading={isLoading} />
            <div className='ui container hidden divider'>
                { properties && properties.length > 0 ? 
                <Grid Columns={3}>
                    <Grid.Column width={2}>
                    <Button as={Link} to='/properties/add-new' style={{ marginTop: '10px' }}>
                        Add More
                    </Button>
                    <Image src='https://wdy.h-cdn.co/assets/16/05/480x480/square-1454612525-baby-pandas.jpg' size='tiny' circular style={{ marginTop: '10px' }}/>
                    </Grid.Column>
                    { content }
                </Grid> : (noPropertiesYetMessage)}
                <Grid.Row style={{width: '100vw', height: '100vh', paddingTop: '15px'}}>
                    <Map markers={markers}/>
                </Grid.Row>
            </div>
        </div>

    )
}

export default PropertyPage

Map组件无需修改

原Map组件逻辑正确,当markers状态更新后,会自动重新渲染所有标记。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 05:45:37