2

I have a map view, and in another componenet, I would like to be able to have a function that animates that mapview. That function would need a reference to my map view. How can I access my maps reference inside another component?

I have a snack expo that reproduces my problem exactly here as well as some code below. Please note which files are classes and which are functions. The files are too big in my projects, I do not want to change them

EDIT: Could I use some sort of state library such as Context to store the ref?

export default function App() {
  return (
    <View style={styles.container}>
      <Map/>
      <AnimateMapButton/>
    </View>
  );
}

I cant access this._map for obvious reasons. How can I access this?

export default class AnimateMapButton extends React.Component {

  goToLocation = () => {
    this._map.animateToRegion({
      latitude: 103.1561,
      longitude: -47.1651,
      latitudeDelta: 0.0025,
      longitudeDelta: 0.0025,
    })
  }

  render() {
  return (
      <View style={{height: 75, width: 200, backgroundColor: 'red', position: 'absolute', top: 100}}>
        <TouchableOpacity onPress={() => this.goToLocation()}>
        <Text style={{fontSize: 20, }}>Click to animate the map</Text>
        </TouchableOpacity>
      </View>
  );
}
}
export default class Map extends React.Component {
  render(){
  return (
    <View style={styles.container}>
      <MapView 
        style={styles.map}
        ref={map => this._map = map}
       />
    </View>
  );
}
}
MouseWarrior
  • 391
  • 4
  • 19

2 Answers2

1

I suggest you use React.forwardRef in such scenarios.

map.js

export default React.forwardRef((props, ref) => {
   return (
    <View style={styles.container}>
      <MapView
        ref={ref}
        style={styles.map}
      />
    </View>
  );
})

animatemapbutton.js

export default class AnimateMapButton extends React.Component {

  render() {
  return (
      <View style={{height: 75, width: 200, backgroundColor: 'red', position: 'absolute', top: 100}}>
        <TouchableOpacity onPress={() => this.props.onGotoLocation()}>
        <Text style={{fontSize: 20, }}>Click to animate the map</Text>
        </TouchableOpacity>
      </View>
  );
}
}

  

App.js

 export default function App() {
       const _mapRef = React.createRef();
    
        goToLocation = () => {
        _mapRef.current.animateToRegion({
          latitude: 103.1561,
          longitude: -47.1651,
          latitudeDelta: 0.0025,
          longitudeDelta: 0.0025,
        })
      }
    
      return (
        <View style={styles.container}>
          <Map ref={_mapRef}/>
          <AnimateMapButton onGotoLocation={goToLocation} />
        </View>
      );
    }
Gavara.Suneel
  • 458
  • 2
  • 14
  • Not sure if this would work. I really need Map to be a class. – MouseWarrior Nov 14 '22 at 16:00
  • 1
    @guts716., You can do that as well using forwardRef. Please add this snippet inside map.js. `class Map extends React.Component { render(){ return ( );}} export default React.forwardRef((props, ref) => )` For more information about forwardRef, Please check this (https://stackoverflow.com/questions/51526461/how-to-use-react-forwardref-in-a-class-based-component) once – Gavara.Suneel Nov 14 '22 at 16:07
  • 1
    Very interesting! No idea this even existed. I am going to check it out once I get home from work. Should reward you your points then! Thank you for the help Gavara. – MouseWarrior Nov 14 '22 at 16:45
  • I edited my example here. The button is not reacting to anything. Any idea why? https://snack.expo.dev/@priedejm/pass-reference-to-component – MouseWarrior Nov 15 '22 at 03:02
  • 1
    I have just downloaded your code and strangely I could able to tap the **Click to animate the map** button. the Map is moving in some directions. – Gavara.Suneel Nov 15 '22 at 05:35
  • Ah yes, I am not sure why it was not working for me. It is now. Could you look at the link I sent above one more time? Your answer created a new question for me that I have here. https://stackoverflow.com/questions/74453756/combining-two-functions-that-wrap-my-class-component – MouseWarrior Nov 16 '22 at 01:20
0

You have to use a combination of reference and event callback method in the root component like this -

App.js

export default function App() {
  const mapRef = React.useRef();

  const goToLocation = () => {
    mapRef.current.animateToRegion({
      latitude: 37.78825,
      longitude: -122.4324,
      latitudeDelta: 0.0922,
      longitudeDelta: 0.0421,
    })
  }

  return (
    <View style={styles.container}>
      <Map mapRef={mapRef} />
      <AnimateMapButton goToLocation={goToLocation} />
    </View>
  );
}

animatemapbutton.js

export default function Animatemapbutton({ goToLocation }) {
  return (
      <TouchableOpacity
        style={{ height: 75, width: 200, backgroundColor: 'red', position: 'absolute', top: 100 }}
        onPress={() => goToLocation()}
      >
        <Text style={{fontSize: 20, }}>Click to animate the map</Text>
      </TouchableOpacity>
  );
}

map.js

export default function Map({ mapRef }) {
  return (
    <View style={styles.container}>
      <MapView
        ref={mapRef}
        style={styles.map}
      />
    </View>
  );
}
vinayr
  • 11,026
  • 3
  • 46
  • 42