我在一個Gatsby專案中為我的Google Maps組件添加標記時失敗了。有人特別要求我不要使用任何第三方庫,如react-google-maps,所以請不要推薦這些庫。我將使用@googlemaps/js-api-loader.
我可以很好地加載地圖,但是我不能讓標記顯示出來。它被創建為一個新的google.maps.Marker,并且記錄結果顯示它正確接收了lng和lat。我已經嘗試了各種方法(承諾、回呼、async/await、不同的作用域等),但似乎markerMaker是在mapMaker之前完成的,盡管我試圖將map作為useEffect鉤的依賴。
我已經嘗試將map存盤為一塊狀態,因為它回傳的是一個承諾,但它仍然只回傳一個承諾,所以我現在只是感到困惑。
代碼如下:
。import React, { useState, useEffect } from "react"。
import { Loader } from "@googlemaps/js-api-loader"
const loader = new Loader({
apiKey: "APIKEY"/span>,
version: "周刊"。
// libraries: ["places"],
})
const mapOptions = {
center: {
lat: -27.4705,
lng: 153.026,
},
zoom: 12,
}
const mapMaker = async ( ) => {
try {
const google = await loader.load()
const map = await new google.maps.Map (
document.getElementById("map"/span>)。
控制元件
)
console.log("map loaded")
return map
} catch (錯誤) {
console.log(錯誤)。
}
}
const markerMaker = async(pos, map)=> {
try {
const google = await loader.load()
const marker = new google.maps.Marker({
position: pos,
setMap: map,
title: "test"。
})
console.log("marker loaded"/span>)
} catch (error) {
console.log(錯誤)。
}
}
const GoogleMap = ({ className, practices }) => {
const [map, setMap] = useState({})
useEffect(() => {
setMap(mapMaker() )
}, [])
useEffect(() => {
markerMaker({ lat: -27.081149410091783, lng: 152.9497979199946 }, map)
}, [map])
return < div className={className} id="map"/span>> </div>
}
export default GoogleMap
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" class="snippet-box-edit snippet-box-result" frameborder="0"></iframe>
如果有任何見解,我們將不勝感激。
uj5u.com熱心網友回復:
鑒于沒有作業實體,我將假設問題是在地圖可用之前運行標記器。
你似乎有兩個不正確的假設:
你在運行的時候有兩個不正確的假設:
useEffect(() => setMap(mapMaker(), [])將把state的值設定為mapMaker的回傳值,即谷歌地圖的一個實體。
useEffect(fn, [maps])將只在第一點的實體被宣告后運行。
在第一點中,實際發生的情況是,函式mapMaker是異步的,因此回傳一個Pomise。因此,你的代碼實際上正在做的是將狀態設定為Promise {<pending>}。為了解決這個問題,你必須將你的代碼改為:
useEffect(( ) => {
mapMaker().then(span class="hljs-params">map => setMap(map) 。
}, [])
// Or if you prefer async / await
const loadMap = async ( ) => {
const map = await mapMaker()。
setMaps(map)。
}
useEffect(() => {
loadMap()
}, [])
現在,由于第二點的存在,僅此一項并不能解決這個問題。當你將一個依賴關系傳遞給useEffect時,它將在初始值以及每一個值的變化中運行。
所以你的代碼有效地并行運行markerMaker和mapMaker。然后當你在第一個useEffect中設定map為Promise {<pending>}時,第二次運行markerMaker。
為了解決這個問題,你需要在運行markerMaker之前檢查map是否已經被設定為google maps的實體。
一個快速修復方法是:
const [map, setMap] = useState(null) //設定初始狀態為null | undefined。
useEffect(() => {
if (map !== null) { //check for the initial value
markerMaker({ lat: -27.081149410091783, lng: 152.9497979199946 }, map)
}
}, [map])
你可以在sandbox中對此進行操作。
uj5u.com熱心網友回復:
這是我想出的作業方案。它有點啰嗦,也不是最漂亮的,但它可以作業。我肯定它可以通過重構來改進,如果我有時間的話,我可能會回來補充。
主要問題是 "地圖 "物件并不是全域存在的。我沒有把它存盤在一塊狀態中,我之前在這樣做時遇到了麻煩,我把它保存為一個變數。
你可能還看到,@MrUpsidown 對 setMap 屬性提出了一個有效的觀點。它確實出現在類上,但我需要用map來代替。 我完全愿意接受批評,以便我可以改進。請提前感謝大家的意見。
。import React, { useState, useEffect, useRef } from "react"
import { Loader } from "@googlemaps/js-api-loader"
const loader = new Loader({
apiKey: "key",
version: "周刊"。
libraries: ["places"]。
})
const mapOptions = {
center: {
lat: -27.4705,
lng: 153.026,
},
zoom: 9,
}
const GoogleMap = ({ className, practices }) => {
const [maps, setMaps] = useState(undefined)
const mapRef = useRef(null)
let map
const mapMaker = mapRef => {
map = new maps.Map(mapRef.current, mapOptions)
}
const markerMaker=(pos, map)=> {
const marker = new maps.Marker({
position: pos,
map: map,
title: "test"。
})
}
const mapsObjectSetter = async ( ) => {
const google = await loader.load()
setMaps(google.maps)
}
useEffect(() => {
mapsObjectSetter()
}, [])
useEffect(() => {
if (! maps) {
回傳。
}
mapMaker(mapRef)
}, [maps])
useEffect(() => {
if (! maps) {
回傳。
}
practices.forEach(item => markerMaker( item.coords, map)
}, [maps])
return < div className={className} ref={mapRef}>。 </div>
}
export default GoogleMap
<iframe name="sif2" sandbox="allow-forms allow-modals allow-scripts" class="snippet-box-edit snippet-box-result" frameborder="0"></iframe>
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/311671.html
標籤:
