Home > Back-end >  pass coordinates from googlemaps react child to parent in functional component typescript
pass coordinates from googlemaps react child to parent in functional component typescript

Time:05-15

I'm using @googlemaps/react-wrapper to make a map component in my react application using the example from googlemaps, and adding an event on drag marker to refresh coordinates, this works fine now. but i need to call the map component outside to refresh a input value with the coordiantes. The error i get it is:

Binding element 'childToParent' implicitly has an 'any' type.* Please could help me to understand how i could send the values to paren using typescript Greetings In parent i have this

 const [coordinate,SetCoordinate]=useState("");  
return (
        <FormProvider methods={methods} onSubmit={handleSubmit(onSubmit)}>
            <Stack spacing={3}>

                <RHFTextField name="lat" label="Coord X" />
                <RHFTextField name="lng" label="Coord Y" />

            </Stack>
            <Stack>
                <br/>
                <LocationMap  childToParent={setCoordinate}/>
            </Stack>
            <Stack>

                <LoadingButton
                    fullWidth
                    size="large"
                    type="submit"
                    variant="contained"
                >
                    Save
                </LoadingButton>
            </Stack>
        </FormProvider>
    );

My Location map component is like this

const render = (status: Status) => {
  return <h1>{status}</h1>;
};
interface MapProps extends google.maps.MapOptions {
  style: { [key: string]: string };
  onClick?: (e: google.maps.MapMouseEvent) => void;
  onIdle?: (map: google.maps.Map) => void;
}
//function to pass value to parent
interface LocationProps {
  childToParent: (arg0: string)=>string;
}
export default function LocationMap({childToParent,...props}){

  const [clicks, setClicks] = useState<google.maps.LatLng[]>([]);
  const [zoom, setZoom] = useState(3); // initial zoom
  const [center, setCenter] = useState<google.maps.LatLngLiteral>({
    lat: 0.0,
    lng: 0.0,
  });
  const [markerLocation, setMarkerLocation] = useState<google.maps.LatLng>();
  const dragend = (e: google.maps.MapMouseEvent) => {
    // avoid directly mutating state
    setMarkerLocation(e.latLng!)
    setClicks([...clicks, e.latLng!]);

  };

  const onClick = (e: google.maps.MapMouseEvent) => {
  };
  const onIdle = (m: google.maps.Map) => {
    //.log("onIdle");
    setZoom(m.getZoom()!);
    setCenter(m.getCenter()!.toJSON());
  };

  const ref = useRef<HTMLDivElement>(null);
  const [map, setMap] = useState<google.maps.Map>();
  useEffect(() => {
    if (ref.current && !map) {
      setMap(new window.google.maps.Map(ref.current, {}));
    }

  }, [ref, map]);

  return (
    <>
      <div style={{ display: "flex", height: "100%" }}>
        <Wrapper apiKey={apiKey} render={render}>
          <Map
            center={center}
            onClick={onClick}
            onIdle={onIdle}
            zoom={zoom}
            style={{ flexGrow: "1", height: "25em", width: "400px" }}
          >


            <Marker key="point" draggable={true} dragend={dragend} />


          </Map>

        </Wrapper>
      </div>
      <div id="coordinate">
        {clicks.map(function (latLng, i, row) {
          var element = document.getElementById("coordenadas");
          if (element === null) {
            console.error("error cleaning coordinates");
          } else {
            element.innerHTML = "";
          }
          return (
          childToParent(latLng.toJSON())
          );
        })
        }
      </div>
    </>
  )
};

interface MapProps extends google.maps.MapOptions {
  onClick?: (e: google.maps.MapMouseEvent) => void;
  onIdle?: (map: google.maps.Map) => void;
}
const Map: React.FC<MapProps> = ({
  onClick,
  onIdle,
  children,
  style,
  ...options
}) => {
  const ref = useRef<HTMLDivElement>(null);
  const [map, setMap] = useState<google.maps.Map>();

  useEffect(() => {
    if (ref.current && !map) {
      setMap(new window.google.maps.Map(ref.current, {}));
    }
  }, [ref, map]);

  // because React does not do deep comparisons, a custom hook is used
  // see discussion in https://github.com/googlemaps/js-samples/issues/946
  useDeepCompareEffectForMaps(() => {
    if (map) {
      map.setOptions(options);
    }
  }, [map, options]);

  useEffect(() => {
    if (map) {
      ["click", "idle"].forEach((eventName) =>
        google.maps.event.clearListeners(map, eventName)
      );

      if (onClick) {
        map.addListener("click", onClick);
      }

      if (onIdle) {
        map.addListener("idle", () => onIdle(map));
      }
    }
  }, [map, onClick, onIdle]);

  return (
    <>
      <div ref={ref} style={style} />
      {Children.map(children, (child) => {
        if (isValidElement(child)) {
          // set the map prop on the child component
          return cloneElement(child, { map });
        }
      })}
    </>
  );
};
interface MarkerProps extends google.maps.MarkerOptions {
  dragend?: (e: google.maps.MapMouseEvent) => void;
}
const Marker: React.FC<MarkerProps> = ({
  dragend,
  ...options
}) => {
  const [marker, setMarker] = useState<google.maps.Marker>();
  console.log(options);

  useEffect(() => {

    if (!marker) {
      setMarker(new google.maps.Marker({
        position: {
          lat: 0,
          lng: 0,
        },
      }));
    }

    // remove marker from map on unmount
    return () => {

      if (marker) {
        marker.setMap(null);
      }
    };
  }, [marker]);

  useEffect(() => {
    if (marker) {
      marker.setOptions(options);
    }
  }, [marker, options]);

  useEffect(() => {
    if (marker) {
      ["dragend"].forEach((eventName) =>
        google.maps.event.clearListeners(marker, eventName)
      );
      marker.setOptions(options);
      if (dragend) {
        //map.addListener("click", onClick);
        marker.addListener("dragend", dragend);

      }
    }
  }, [marker, dragend, options]);

  return null;
};
const deepCompareEqualsForMaps = createCustomEqual(
  (deepEqual) => (a: any, b: any) => {
    if (
      isLatLngLiteral(a) ||
      a instanceof google.maps.LatLng ||
      isLatLngLiteral(b) ||
      b instanceof google.maps.LatLng
    ) {
      return new google.maps.LatLng(a).equals(new google.maps.LatLng(b));
    }

    // TODO extend to other types

    // use fast-equals for other objects
    return deepEqual(a, b);
  }
);

function useDeepCompareMemoize(value: any) {
  const ref = useRef();

  if (!deepCompareEqualsForMaps(value, ref.current)) {
    ref.current = value;
  }

  return ref.current;
}

function useDeepCompareEffectForMaps(
  callback: React.EffectCallback,
  dependencies: any[]
) {
  useEffect(callback, dependencies.map(useDeepCompareMemoize));
}
export default LocationMap;

CodePudding user response:

It is warning you because you have not passed the correct function. This should fix the problem:

const [coordinate, setCoordinate] = useState("");
  • Related