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> ) : ( <></> ); }