react-native-maps: Cannot call ref for methods on < MapView /> when using Function Components + Hooks

Question

I found this StackOverflow post with similar information on how this could be figured out and resolved, however I tried with both the useRef and createRef hooks and neither was able to capture a reference to the map in the way I can actually call a method on it.

https://stackoverflow.com/questions/41048546/how-can-i-attach-to-a-stateless-components-ref-in-react

One example:

import React, { createRef }, from "react"

<ommitted>

const ServiceMap = ({service, driver}) => {

let mapRef = createRef();

return (
<MapView
ref={mapref}
>

</MapView>
)

}

No matter what when I use the patterns and proposed solutions I get the following value from my “mapRef”:

Object {
  "current": null,
}

Then when I try to call one of the methods on it, I am told that it is undefined. When I look up all of the documentation about how to use Refs, then I am never shown with this format, however this is the consistent way I am building my entire application with hooks. I would want to stay consistent with this approach.

When I read this article: https://www.robinwieruch.de/react-function-component I find that “React Function Components cannot have refs. However, if you need to pass a ref to a Function Component – because you have to measure the size of a function component’s DOM node, for example, or like in this case to focus an input field from the outside – you can forward the ref:”

So then let me try to forward the ref, ok. Hold on, I cannot because I did not create the component and I cannot modify the “<MapView>” component itself, I am importing it from this library!

Is there a solution here? Does this mean it is impossible to call methods on the components if I am using this approach? To clarify I can display the map, markers, etc. all just fine.

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 5
  • Comments: 16

Most upvoted comments

@dragma How are you trying to access the methods? Can you show us what you’re trying to do and what error you’re getting?

FYI, make sure you’re accessing the methods through the .current property, i.e as mapRef.current.methodName

Same thing here. I can’t have acces to any method in my MapView’s ref. Code is almost the same, the “major” difference here is that I use useRef.

Code example :

import React, { useRef } from 'react';
import MapView from 'react-native-maps';

const MyComp = () => {
    const mapRef = useRef(null);
    return (
      <MapView ref={mapRef} onMapReady={() => console.log(mapRef)}>[...myMarkers...]</MapView>
    ); 
}

I am using expo v35, and react-native-maps v0.25.0

Hello All, having same issue. Cant access methods animateToRegion when add reference with useRef(). Does anybody has working example with hooks?

Please try ref.current

const mapRef = useRef(null);
mapRef.current.animateToRegion

For me this is working partially.

I have a component <MapView ref={map} /> and a const map = useRef(null); declaration in a FunctionComponent. From within a useEffect effect callback I can call map.current.fitToCoordinates() for instance, which is working great. But from within an onChangeText handler of a <TextInput/> in the same component, the map.current reference is null.

Does anyone have any idea how to fix this?

Hello All, having same issue. Cant access methods animateToRegion when add reference with useRef(). Does anybody has working example with hooks?

I am trying to access the method by the mapRef variable. The output I get with this code

import React, { useRef } from 'react';
import MapView from 'react-native-maps';

const MyComp = () => {
    const mapRef = useRef(null);
    return (
    <MapView 
        ref={mapRef} 
        onMapReady={() => {
            console.log('==> REF CURRENT OBJECT KEYS');
            console.log(Object.keys(mapRef.current));
            console.log('==> TYPE OF EACH METHODS');
            console.log('mapRef.current.getCamera => ', typeof mapRef.current.getCamera);
            console.log('mapRef.current.animateCamera => ', typeof mapRef.current.animateCamera);
            console.log('mapRef.current.setCamera => ', typeof mapRef.current.setCamera);
            console.log('mapRef.current.animateToRegion => ', typeof mapRef.current.animateToRegion);
            console.log('mapRef.current.animateToNavigation => ', typeof mapRef.current.animateToNavigation);
            console.log('mapRef.current.animateToCoordinate => ', typeof mapRef.current.animateToCoordinate);
            console.log('mapRef.current.animateToBearing => ', typeof mapRef.current.animateToBearing);
            console.log('mapRef.current.animateToViewingAngle => ', typeof mapRef.current.animateToViewingAngle);
            console.log('mapRef.current.getMapBoundaries => ', typeof mapRef.current.getMapBoundaries);
            console.log('mapRef.current.setMapBoundaries => ', typeof mapRef.current.setMapBoundaries);
            console.log('mapRef.current.setIndoorActiveLevelIndex => ', typeof mapRef.current.setIndoorActiveLevelIndex);
            console.log('mapRef.current.fitToElements => ', typeof mapRef.current.fitToElements);
            console.log('mapRef.current.fitToSuppliedMarkers => ', typeof mapRef.current.fitToSuppliedMarkers);
            console.log('mapRef.current.fitToCoordinates => ', typeof mapRef.current.fitToCoordinates);
            console.log('mapRef.current.pointForCoordinate => ', typeof mapRef.current.pointForCoordinate);
            console.log('mapRef.current.coordinateForPoint => ', typeof mapRef.current.coordinateForPoint);
            console.log('mapRef.current.getMarkersFrames => ', typeof mapRef.current.getMarkersFrames);
            console.log('==> TEST GET CAMERA');
            mapRef.current.getCamera();
        }} />
    ); 
}

is this one

==> REF CURRENT OBJECT KEYS
Array [
  "props",
  "context",
  "refs",
  "updater",
  "state",
  "_onMapReady",
  "_onMarkerPress",
  "_onChange",
  "_onLayout",
  "_reactInternalFiber",
  "_reactInternalInstance",
  "__reactInternalMemoizedMergedChildContext",
  "map",
  "__reactInternalSnapshotBeforeUpdate",
]
==> TYPE OF EACH METHODS
mapRef.current.getCamera =>  function
mapRef.current.animateCamera =>  function
mapRef.current.setCamera =>  function
mapRef.current.animateToRegion =>  function
mapRef.current.animateToNavigation =>  function
mapRef.current.animateToCoordinate =>  function
mapRef.current.animateToBearing =>  function
mapRef.current.animateToViewingAngle =>  function
mapRef.current.getMapBoundaries =>  function
mapRef.current.setMapBoundaries =>  function
mapRef.current.setIndoorActiveLevelIndex =>  function
mapRef.current.fitToElements =>  function
mapRef.current.fitToSuppliedMarkers =>  function
mapRef.current.fitToCoordinates =>  function
mapRef.current.pointForCoordinate =>  function
mapRef.current.coordinateForPoint =>  function
mapRef.current.getMarkersFrames =>  function
==> TEST GET CAMERA

TypeError: TypeError: null is not an object (evaluating '_reactNative.NativeModules.AirMapModule.getCamera')
- node_modules/react-native-maps/lib/components/MapView.js:630:40 in getCamera
* src/views/HomeScreen/components/Map.js:149:12 in onMapReady
- node_modules/react-native-maps/lib/components/MapView.js:586:18 in <unknown>
- node_modules/react-native/Libraries/Renderer/oss/ReactNativeRenderer-dev.js:13857:16 in callCallback
- ... 22 more stack frames from framework internals

Any clue ?

Hey @mvuk.

So in MapView you attach the ref as mapref, but you’ve defined it as mapRef further above. Fix the typo where you attach the ref in MapView and you’re good to go. It should work.

Now, it’s true that functional components cannot have refs, in the sense that you can’t attach a ref to them. This is not what you’re doing here. You’re attaching a ref to MapView which is not a functional component, it’s a class component. So you shouldn’t worry about that.

As for createRef() vs useRef(), you should generally prefer useRef() in functional components since you probably want to maintain the reference across updates.