I have a question of something that looks pretty obvious but It’s getting hard for me. I know that for fetching data that will get actually rendered in a component you need to use reacthooks and useState. However I am having a problem because I need to fetch some data and then store it in a variable that it’s not part of the component rendering. This is my current code.
import React from 'react'
import { GoogleMap, useJsApiLoader } from '@react-google-maps/api';
import { GoogleMapsOverlay } from "@deck.gl/google-maps";
import {GeoJsonLayer, ArcLayer} from '@deck.gl/layers';
import axios from 'axios';
import {useState} from 'react';
const hasWindow = typeof window !== 'undefined';
function getWindowDimensions() {
const width = hasWindow ? window.innerWidth : null;
const height = hasWindow ? window.innerHeight : null;
return {
width,
height,
};
}
const center = {
lat: 51.509865,
lng: -0.118092
};
const deckOverlay = new GoogleMapsOverlay({
layers: [
new GeoJsonLayer({
id: "airports",
data: markers,
filled: true,
pointRadiusMinPixels: 2,
opacity: 1,
pointRadiusScale: 2000,
getRadius: f => 11 - f.properties.scalerank,
getFillColor: [200, 0, 80, 180],
pickable: true,
autoHighlight: true
}),
new ArcLayer({
id: "arcs",
data: markers,
dataTransform: d => d.features.filter(f => f.properties.scalerank < 4),
getSourcePosition: f => [-0.4531566, 51.4709959], // London
getTargetPosition: f => f.geometry.coordinates,
getSourceColor: [0, 128, 200],
getTargetColor: [200, 0, 80],
getWidth: 1
})
]
});
export default function Map() {
const { isLoaded } = useJsApiLoader({
id: 'lensmap',
googleMapsApiKey: "YOUR_API_KEY"
})
const onLoad = React.useCallback(function callback(map) {
deckOverlay.setMap(map)
}, [])
const onUnmount = React.useCallback(function callback(map) {
}, [])
return isLoaded ? (
<GoogleMap
mapContainerStyle={getWindowDimensions()}
center={center}
zoom={10}
onLoad={onLoad}
onUnmount={onUnmount}
>
<></>
</GoogleMap>
) : <></>
}
As you can see GoogleMapsOverlay receives a markers object in it’s constructor, here I would get my markers doing a call to an API using axios but everything that I’ve tested ends in a 500 code when loading the page.
Advertisement
Answer
I assume that you’re asking for a way to fetch the markers and make everything load in the correct order. I think you could store the deckOverlay instance in a ref, fetch the markers in a useEffect hook, update the layers with the markers data, and set a flag to hold from rendering the map until the layers are updated.
import React, { useState, useRef, useEffect, useCallback } from "react";
import { GoogleMap, useJsApiLoader } from "@react-google-maps/api";
import { GoogleMapsOverlay } from "@deck.gl/google-maps";
import { GeoJsonLayer, ArcLayer } from "@deck.gl/layers";
import axios from "axios";
const hasWindow = typeof window !== "undefined";
function getWindowDimensions() {
const width = hasWindow ? window.innerWidth : null;
const height = hasWindow ? window.innerHeight : null;
return {
width,
height,
};
}
const center = {
lat: 51.509865,
lng: -0.118092,
};
export default function Map() {
const { isLoaded } = useJsApiLoader({
id: "lensmap",
googleMapsApiKey: "AIzaSyBmSBtlYQLH8jvAxrdgZErUdtdWLEs40gk",
});
const [markersLoaded, setMarkersLoaded] = useState(false);
const deckOverlay = useRef(new GoogleMapsOverlay({ layers: [] }));
const fecthMarkers = useCallback(async () => {
try {
const response = await axios.get(`someapi.com/markers`);
// assuming API response will have a markers field
const markers = response.data.markers;
deckOverlay.current.setProps({
layers: [
new GeoJsonLayer({
id: "airports",
data: markers,
filled: true,
pointRadiusMinPixels: 2,
opacity: 1,
pointRadiusScale: 2000,
getRadius: (f) => 11 - f.properties.scalerank,
getFillColor: [200, 0, 80, 180],
pickable: true,
autoHighlight: true,
}),
new ArcLayer({
id: "arcs",
data: markers,
dataTransform: (d) =>
d.features.filter((f) => f.properties.scalerank < 4),
getSourcePosition: (f) => [-0.4531566, 51.4709959], // London
getTargetPosition: (f) => f.geometry.coordinates,
getSourceColor: [0, 128, 200],
getTargetColor: [200, 0, 80],
getWidth: 1,
}),
],
});
setMarkersLoaded(true);
} catch (e) {
// TODO: show some err UI
console.log(e);
}
}, []);
useEffect(() => {
fecthMarkers();
},[]);
const onLoad = React.useCallback(function callback(map) {
deckOverlay.current?.setMap(map);
}, []);
const onUnmount = React.useCallback(function callback(map) {
deckOverlay.current?.finalize();
}, []);
return markersLoaded && isLoaded ? (
<GoogleMap
mapContainerStyle={getWindowDimensions()}
center={center}
zoom={10}
onLoad={onLoad}
onUnmount={onUnmount}
>
<></>
</GoogleMap>
) : (
<></>
);
}