Devil's Dream
Devil's Dream

Reputation: 715

Access child function within a default function

I am trying to add some markers on Map. Here I have added a custom addMarker function. I want to pass myGeoJson param from a buttonClick of another component

export default function Map() {
  const mapContainer = useRef(null);
  const map = useRef(null);
  const [lng] = useState(91.638);
  const [lat] = useState(23.735);
  const [zoom] = useState(6.5);
  const [API_KEY] = useState('YOUR_MAPBOX_API_KEY');

  useEffect(() => {
    if (map.current) return;
    map.current = new mapboxgl.Map({
      container: mapContainer.current,
      style: `style.json`,
      center: [lng, lat],
      zoom: zoom,
      maxZoom: 22,
      minZoom: 6
    });
  });

  const addMarkers = (myGeoJson) => {
    map.current.addSource('points', {
      'type': 'geojson',
      'data': myGeoJson
    });
  
    // Add a symbol layer
    map.current.addLayer({
      'id': 'points-1',
      'type': 'symbol',
      'source': 'points',
      'layout': {
        'icon-image': 'icon-12',
        'text-field': ['get', 'title'],
        'text-font': [
          'roboto',
          'MuliBold'
        ],
        'text-offset': [0, 0.5],
        'text-anchor': 'top'
      }
    });
  }
  
  return (
    <div className="map-wrap">
      <div ref={mapContainer} className="map" />
    </div>
  );
}

Now the second container is

import {addMarkers} from './map'

export const SideBar = props => {
    ///getting myGeoJson data by calling API
    ...
    const onClick = () => {
        addMarkers(myGeoJson);
    };
    ...
    return (
      <div>
        <Button onClisk={onClick}>Draw Markers</Button>
      </div>
}

But the addMarkers() can not be accessible from Map()

Upvotes: 0

Views: 22

Answers (1)

Xiduzo
Xiduzo

Reputation: 1311

You are pretty close to your solution. In order to access the addMarkers method from the Map component you should wrap it with a forwardRef.

Doing so can expose some methods to sibling components, like your Button

An working example can be found at code-sandbox

Example:

// Map.js
import { forwardRef, useImperativeHandle } from "react";

export const Map = forwardRef((props, ref) => {
  const addMarkers = (myGeoJson) => {
    console.log("addMarkers", myGeoJson);
    alert("Added marker: " + JSON.stringify(myGeoJson));
  };

  useImperativeHandle(ref, () => ({
    addMarkers
  }));

  return <div>map</div>;
});
// Button.js
export const Button = ({ onClick }) => {
  return (
    <div>
      <button onClick={onClick}>Draw Markers</button>
    </div>
  );
};
// App.js
import { Button } from "./Button";
import { Map } from "./Map";
import { useRef } from "react";

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

  const onClick = () => {
    if (mapRef.current === undefined) return; // Map ref is not set yet

    mapRef.current.addMarkers({ lat: 123.345, lon: 44.345 });
  };
  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <h2>Start editing to see some magic happen!</h2>
      <Button onClick={onClick} />
      <Map ref={mapRef} />
    </div>
  );
}

Upvotes: 1

Related Questions