Skip to content
Advertisement

Fetching data for another variable react

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>
  ) : (
    <></>
  );
}
User contributions licensed under: CC BY-SA
6 People found this is helpful
Advertisement