Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

react-native-maps callout content not updated on change

I am trying to update the content of a <Callout> tag on a google maps view using the react-native-maps npm package. I would like to dynamically load extra content after a map marker is pressed. I have simplified my code to the example below:-

I have already tried using the tracksInfoWindowChanges attribute on the marker, and the showCallout() method to attempt to manually trigger a re-render. I am using android so the iOS only options such as redrawCallout() method are not available.

const MyMap = (props) => {
    const [marker, setMarker] = useState({});

    return (
        <MapView
            showsUserLocation
            zoomControlEnabled={true}
            zoomEnabled={true}
            region={{
                latitude: 0,
                longitude: 0,
                latitudeDelta: 0.03,
                longitudeDelta: 0.03,
            }}>
            <Marker
                coordinate={{latitude: 0, longitude: 0}}
                onPress={(e) => {
                    setMarker({ title: 'Test'});           
                }}>
                 <View>
                     <Icon name='key' size={40} color='#384963'</Icon> 
                 </View>
                 <Callout>
                    <Text>{marker.title}</Text>              
                 </Callout>
             </Marker>
        </MapView>
    );
}

Is it possible to trigger a re-render of the content after the Callout has been rendered once? From debugging I can see that the component renders after I update my marker state, however the content is not visible until I manually close the Callout and re-opened it.

like image 288
Laura Avatar asked Dec 02 '25 10:12

Laura


1 Answers

I am having the exact same problem. The suggestion for android, as per this issue, is to use showCallout(). Below is my work-around for this issue using showCallout():

const MyMap = (props) => {
    const [marker, setMarker] = useState({});
    let markerRef = useRef(null);

    useEffect(() => {
        if (markerRef.current) {
            markerRef.current.showCallout();
        }
    })

    return (
        <MapView
            showsUserLocation
            zoomControlEnabled={true}
            zoomEnabled={true}
            region={{
                latitude: 0,
                longitude: 0,
                latitudeDelta: 0.03,
                longitudeDelta: 0.03,
            }}>
            <Marker
                ref={markerRef}
                coordinate={{latitude: 0, longitude: 0}}
                onPress={(e) => {
                    setMarker({title: `Test ${Math.floor(Math.random() * 10)}`});         
                }}>
                 <View>
                     <Icon name='key' size={40} color='#384963' /> 
                 </View>
                 <Callout>
                    <Text>{marker.title}</Text>              
                 </Callout>
             </Marker>
        </MapView>
    );
}

Briefly, I added a markerRef and call markerRef.current.showCallout() in useEffect(). What this achieves, if I am not mistaken, is that each time MyMap gets re-rendered, the callout will be forced to show again. I also changed the onPress such that the effect of callout re-rendering is more apparent.

Note 1: Each time the marker is pressed, the callout shall have its text updated.

Note 2: If you have multiple markers and callouts, and you want to update only the callout that is currently in view, you will have to add another check in useEffect(). Something like: if (markerRef.current && selectedMarker === 'markerID') to make sure that only the desired callout is re-rendered continuously.

like image 198
Fanchen Bao Avatar answered Dec 05 '25 11:12

Fanchen Bao



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!