Background
I am working on a website where I have parent components and child components. The snippet below is a Google Map wrapper and a map component.
Code
import React, { useEffect, useState, useRef } from "react";
// reactstrap components
import { Card, Container, Row } from "reactstrap";
// core components
import Header from "components/Headers/Header.js";
import LocationSearchInput from "../../components/Places";
import { useAuthenticator } from "@aws-amplify/ui-react";
import * as queries from "../../graphql/queries";
import { API, graphqlOperation } from "aws-amplify";
import { geocodeByAddress, getLatLng } from "react-places-autocomplete";
import * as _ from "lodash";
import { collapseTextChangeRangesAcrossMultipleVersions } from "typescript";
const MapWrapper = (data, loc) => {
const mapRef = useRef(null);
console.log("child props", data, loc);
console.log("foo child", loc);
// THIS WONT WORK BECAUSE WHEN IT FIRST LOADS ITS EMPTY
// geocodeByAddress(loc[0].HomeLocation)
// .then(results => getLatLng(results[0]))
// .then(latLng => console.log('Success', latLng))
// .catch(error => console.error('Error', error))
useEffect(() => {
console.log("child mount");
let google = window.google;
let map = mapRef.current;
let lat = "40.748817";
let lng = "-73.985428";
const myLatlng = new google.maps.LatLng(lat, lng);
const mapOptions = {
zoom: 12,
center: myLatlng,
scrollwheel: false,
zoomControl: true,
styles: [
{
featureType: "administrative",
elementType: "labels.text.fill",
stylers: [{ color: "#444444" }],
},
{
featureType: "landscape",
elementType: "all",
stylers: [{ color: "#f2f2f2" }],
},
{
featureType: "poi",
elementType: "all",
stylers: [{ visibility: "off" }],
},
{
featureType: "road",
elementType: "all",
stylers: [{ saturation: -100 }, { lightness: 45 }],
},
{
featureType: "road.highway",
elementType: "all",
stylers: [{ visibility: "simplified" }],
},
{
featureType: "road.arterial",
elementType: "labels.icon",
stylers: [{ visibility: "off" }],
},
{
featureType: "transit",
elementType: "all",
stylers: [{ visibility: "off" }],
},
{
featureType: "water",
elementType: "all",
stylers: [{ color: "#5e72e4" }, { visibility: "on" }],
},
],
};
map = new google.maps.Map(map, mapOptions);
const marker = new google.maps.Marker({
position: myLatlng,
map: map,
animation: google.maps.Animation.DROP,
title: "Light Bootstrap Dashboard PRO React!",
});
const contentString =
'<div class="info-window-content"><h2>Light Bootstrap Dashboard PRO React</h2>' +
"<p>A premium Admin for React-Bootstrap, Bootstrap, React, and React Hooks.</p></div>";
const infowindow = new google.maps.InfoWindow({
content: contentString,
});
google.maps.event.addListener(marker, "click", function () {
infowindow.open(map, marker);
});
}, []);
console.log("child render");
return (
<>
<div
style={{ height: `600px` }}
className="map-canvas"
id="map-canvas"
ref={mapRef}
></div>
</>
);
};
const Maps = () => {
const [foo, setFoo] = useState([]);
const { user, signOut } = useAuthenticator((context) => [context.user]);
// console.log("user map", user);
const [pin, setPin] = useState([]);
const fetchFoo = async () => {
console.log(user.attributes.email);
try {
const todoData = API.graphql(
graphqlOperation(queries.listEmployees, {
filter: {
Email: {
eq: user.attributes.email,
},
},
})
).then((response) => {
console.log("fetch resp", response);
setFoo(response.data.listEmployees.items);
})
.catch((err) => {
console.log(err);
});
} catch (err) {
console.log("error facing Todos:", err);
}
};
console.log("parent render");
useEffect(() => {
console.log("parent mount")
fetchFoo();
}, []);
var json = [{a: "a", b:"b"}]
return (
<>
<Header />
{/* Page content */}
{/* {foo} */}
<Container className="mt--7" fluid>
<Row>
<div className="col">
{/* <LocationSearchInput /> */}
</div>
</Row>
<Row>
<div className="col">
<Card className="shadow border-0">
{/* <> */}
<MapWrapper data={json} loc={{foo}}/>
{/* </> */}
</Card>
</div>
</Row>
</Container>
</>
);
};
export default Maps;
Output
Problem
The child component when it first reads the data it is empty but it is populated the second time it is loaded. I have tried to tweak the useEffect to work but the only difference I get is it’ll perform an infinite loop if I remove the empty array.