Very simple case, but I can’t find the way out!
I have a Google map with a single marker. The "click" listener callback function logs the state’s value.
I added a button that changes the state’s value, and a useEffect
hook that logs the state value when it is changed, just to check it has changed.
Problem: when I change the state value from "false" to "true" with the button, the hook is triggered and logs the new value ("true"), so I’m pretty sure the state has changed. BUT when I click on the marker, it still returns the previous value ("False") of the state.
How can I get the marker "click" callback to use the updated value of the state?
Thank you for your help, I’m stuck and I could find no support on this issue!
My code (a small and simplified extract of a bigger project!).
import { useEffect, useCallback, useState } from "react";
import { GoogleMap, useJsApiLoader } from "@react-google-maps/api";
import Box from '@mui/material/Box';
export default function MapPage() {
const [state, setState] = useState(false)
// GoogleMap loading with @react-google-maps/api
const { isLoaded } = useJsApiLoader({
id: 'google-map-script',
googleMapsApiKey: "MY-API-KEY"
})
// Marker creation with officiel GoogleMaps API
const onLoad = useCallback(function callback(map) {
let marker = new window.google.maps.Marker({
map: map,
position: { lat: 43.3318, lng: 5.0550 },
icon : { url : "/static/NotSubscribed.svg", scaledSize : {width:60, height:60}}
});
marker.addListener("click", () => {console.log("Marker clicked - State is : " + state)});
}, [])
// useEffect to display new state when value changed
useEffect(() => {
console.log("useEffect - State is : " + state)
}, [state])
return (isLoaded ? (
<Box width="100%" height="100%">
<GoogleMap
mapContainerStyle={{ position: "fixed", height:"100%", width: "100%"}}
center={{ lat: 43.3318, lng: 5.0550 }}
zoom={15}
onLoad={onLoad}
>
</GoogleMap>
<Box sx={{position : "fixed", top : 200, right : 200, width : 50, height : 50, backgroundColor : "black"}}
onClick={() => setState(true)}
/>
</Box>
) : <></>
)
};
2
Answers
since dependency array is empty, this function is created once and reads state when the function is built. Although, you are adding
[state]
to useuseEffect
, this rerenders the component but it does not re create theuseCallback
callback function. you have to add same dependency[state]
to useuseCallback
You could use
<Marker />
component with onClick props fromreact-google-maps/api
libraryWhat @Yilmaz said is correct, but since you are also using
react-google-maps/api
library, it would be much simpler for you to use<Marker />
component since it has anonClick
prop.ref: https://react-google-maps-api-docs.netlify.app/#marker
Here’s what you can do:
Create a
changeState
function to toggle the state betweentrue
andfalse
using ternary operator (This is just for testing).Create a
markerClicked
function to put on your<Marker />
onClick
props.Then here’s what your components should look like along with these changes:
With this, when the map gets loaded, it logs
useEffect - State is : false
since that was your defaultstate
value. Then when you click on the marker, it will also log the current stateMarker clicked - State is : false
.To test if it is working properly, you can toggle the state between
true
andfalse
by clicking the box, then clicking the marker after it to see if the returned state is the same.Here’s a working sandbox for you to test for yourself:
https://codesandbox.io/s/proof-of-concept-sandbox-log-the-state-per-marker-click-and-change-state-per-box-click-ok4vc0?file=/src/Map.js
Hope this helps.