我正在使用MapBox在用户个人资料上显示地图。该组件会接收位置的道具,但是mapbox会在接收到道具之前尝试使用该位置渲染地图,从而破坏页面。我使用了一种解决方法来使其正常工作...但是不确定我是否做对了-您有什么建议吗?我的解决方法是使用useEffect Hook设置viewPort状态...这迫使地图在加载之前等待一秒钟,以便有时间接收道具。我有一种感觉,如果没有及时收到道具,它仍然会损坏。
我还想将用户的位置用作地图的中心点,该点当前在useEffect挂钩中设置-但在设置之前无法获取道具。谢谢!
import React, { useState, useEffect } from 'react';
import Geocode from "react-geocode";
import ReactMapGL, { Marker } from 'react-map-gl';
import { Label, Input, Card, Badge, Button, InputGroup,
} from 'reactstrap';
// set response language. Defaults to english.
Geocode.setLanguage("en");
// set response region. Its optional.
// A Geocoding request with region=es (Spain) will return the Spanish city.
Geocode.setRegion("es");
// set Google Maps Geocoding API for purposes of quota management. Its optional but recommended.
Geocode.setApiKey("******************************");
export default function Location(props) {
const [ city, setCity ] = useState('');
const [ viewPort, setViewport ] = useState({})
useEffect(() => {
setTimeout(() => {
setViewport({
latitude: 37.0902,
longitude: -95.7129,
width: '100%',
height: '200px',
zoom: 3
})
},1000)
}, [])
const captureCity = (e) => {
setCity(e.target.value);
}
const handleLocationInput = () => {
// Get latidude & longitude from address.
Geocode.fromAddress(city).then(
response => {
const { lat, lng } = response.results[0].geometry.location;
putLocation(lat, lng);
},
error => {
console.error(error);
}
);
}
const putLocation = (lat, lon) => {
props.updateBandLocation([lat,lon]);
}
return (
<div>
<div className="w-100">
<ReactMapGL
className="mt-2 mb-4 rounded"
style={{zIndex: "2"}}
{...viewPort}
mapboxApiAccessToken={"******************"}
onViewportChange={viewport => setViewport(viewport)}
mapStyle="mapbox://styles/nickisyourfan/ck8ylgfk90kcb1iqoemkes76u"
>
<Marker latitude={props.bandLocation[0]} longitude={props.bandLocation[1]}>
<img src="/MapMarker.svg" alt="Band Icon" style={{width: "35px", height: "35px"}}/>
</Marker>
</ReactMapGL>
</div>
<Card color="dark" className="mb-1">
<InputGroup className="d-flex flex-column justify-content-center">
<Label className="d-flex flex-column text-light h3 mt-2 align-self-center">Location</Label>
<Input type="text" onChange={captureCity} className="d-flex align-self-center w-75 mb-2"/>
<Button onClick={handleLocationInput} className="w-75 align-self-center mb-2">Set Location</Button>
</InputGroup>
</Card>
</div>
)
}
答案 0 :(得分:0)
在这种情况下,我不会使用setTimeout。
在获得所有期望的地图数据之前,我不会渲染地图。 我将其添加到我的return语句上方。
if (!props.bandLocation.length || !props.bandLocation[0] || !props.bandLocation[1]) {
return <MyCustomLoadingComp />
}
在您的特定情况下,我不确定地图到底需要哪个道具或数据结构,但是您可以理解这个概念。例如,如果props.bandLocation [0]是一个空对象,它将仍然标记为true,因此您必须更改if语句以匹配要接收的数据。
更新: 您可能想使用类似“ usePrevious”帮助函数的方法。与componentWillReceiveProps相似,仅在获得特定项目时才需要在UI中进行更新。因此,在这种情况下,您可以检查是否有有效的经/纬度,然后使用useState进行设置。我需要使用钩子来复制此生命周期方法,并且从https://usehooks.com/usePrevious/开始改编。但是,仍然建议直接使用道具。您可以将道具名称传递给useEffect,当其更改时,组合将重新呈现。
所以
const [loaded, setLoaded] = useState(lat);
useEffect(() => {
setLoaded(false);
if (isAValidLocation(props.lat)) {
setLoaded(true);
}
}, [props.lat, props.long]);
不过,直率地说,您应该在地图具有所有相关数据之前不渲染地图,如果您不以任何方式操纵道具的内容,则无需使用任何生命周期挂钩。