I am working with a map inside a NextJS app, using GoogleMap. Below is the component displaying the map.
It mostly works as I expect.
function Map({latitude,longitude}:
{latitude:number,longitude:number}) {
const center = useMemo(() => ({
lat: latitude,
lng: longitude
}), []);
return (
<GoogleMap zoom={17} center={center}
mapContainerClassName="map-container">
<Marker position={center} />
</GoogleMap>
);
} /* End of Map */
The component above is used inside this other component:
export default function GeoMap(
{shop,gps}:
{shop: string, gps: string;}
) {
const [theGPS, setTheGPS] =
useState({coords:{latitude:0.0,longitude:0.0}})
const [theLatitude, setLatitude] = useState(0.0)
const [theLongitude, setLongitude] = useState(0.0)
const dbRef = ref(firebaseDatabase, 'MyApp/'+shop)
useEffect(() => {
onValue(dbRef, (snapshot) => {
const coordsStr = snapshot.child('gPS').val().split(','),
latit = parseFloat(coordsStr[0]),
longit = parseFloat(coordsStr[1])
console.log('shop='+shop)
console.log('coordsStr='+coordsStr)
console.log('latit='+latit.toString())
console.log('longit='+longit.toString())
setTheGPS({coords: {latitude:latit, longitude:longit}})
setLatitude(latit); setLongitude(longit)
}, (error) => {
console.log('Error(onValue): '+error);
});
}, [])
useEffect(() => { // Not needed. Just for test.
setLatitude(theGPS.coords.latitude);
setLongitude(theGPS.coords.longitude)
}, [theGPS])
.....
return <Map latitude= {theLatitude}
longitude= {theLongitude} />
} /* End of GeoMap */
But I have the following issue:
When the values of theLatitude and theLongitude change (due to some external action) I can see it happen in the logs as expected, but the display in the map is not updated. Why is that?
If I do a manual page reloading, I can of course see the map updating adequately; but I want to have the map update itself without having to manually reload. Since theLatitude and theLongitude are state variables I would expect the map to automatically update itself.
I managed to reproduce the problem using a stub GoogleMap
. The issue got resolved after adding dependencies to useMemo
in the Map
component:
const center = useMemo(() => ({
lat: latitude,
lng: longitude
}), [latitude, longitude]);
Here is the rest of the code I used to reproduce:
export function GeoMap() {
const [theGPS, setTheGPS] =
useState({coords:{latitude:0.0,longitude:0.0}})
const [theLatitude, setLatitude] = useState(0.0)
const [theLongitude, setLongitude] = useState(0.0)
useEffect(() => { // Not needed. Just for test.
setLatitude(theGPS.coords.latitude);
setLongitude(theGPS.coords.longitude)
}, [theGPS])
return <div>
<button onClick={() => {
console.log('Clicked')
setLatitude(theLatitude + 1)
setLongitude(theLongitude + 1)
}}>render</button>
<Map latitude= {theLatitude}
longitude= {theLongitude} />
</div>
}
function Map({latitude,longitude}:
{latitude:number,longitude:number}) {
// THE FIX
const center = useMemo(() => ({
lat: latitude,
lng: longitude
}), [latitude, longitude]);
// PREVENTS RERENDER
// const center = useMemo(() => ({
// lat: latitude,
// lng: longitude
// }), []);
return <GoogleMap center={center} zoom={17}/>
}
function GoogleMap({center, zoom }: {center: {lat:number,lng:number}, zoom: number}) {
return <div>
<div>{center.lat}</div>
<div>{center.lng}</div>
</div>
}