DEV Community

loading...
Cover image for Project 59 of 100 - React Wildfire Tracker

Project 59 of 100 - React Wildfire Tracker

jwhubert91 profile image James Hubert ・3 min read

Hey! I'm on a mission to make 100 React.js projects ending March 31st. Please follow my dev.to profile or my twitter for updates and feel free to reach out if you have questions. Thanks for your support!

Link to the deployed project: Link
Link to the repo: github

This was a quick video, and I actually had a blast doing it. I'm sometimes not the biggest fan of Brad Traversy's long form videos because I don't feel I absorb much with code-along tutorials, but shorter videos covering material you mostly know and want practice with are excellent and his video creating a React Wildfire Tracker fit the bill for a late Saturday night coding session.

The data for this website comes from NASA. This was my first time using their API so that was a pleasure. We made use of their Events API which tracks natural events going on in the world. This was also my first app using Google Maps. In previous projects I had opted for Mapbox because it was free, but I do enjoy Google Maps' bright color scheme that feels like a real map (vs an app) and easy navigation. To display the map in React I used the google-map-react npm package.

Other npm packages I made use of included LoaderSpinner for an animated spinner on loading screens, the Iconify icon package at @iconify/react and specifically their Material Design icon library at @iconify/icons-mdi. I also used dotenv to save sensitive API info in process variables. I accidentally forgot to put the Header in my components folder. Forgive me for it.

First, in our App component we import useState and useEffect from the React package. We then create two pieces of state- loading and eventData. Loading will be a boolean that indicates whether the data is being fetched. We will use it to display a loading spinner if it is true. eventData will be an empty array until our fetch method returns data. We'll use useEffect to fetch data from the API on page load.

import React,{useState,useEffect} from 'react'
import LoaderSpinner from './components/LoaderSpinner'
import Map from './components/Map'
import Header from './Header'

function App() {
  const [eventData,setEventData] = useState([])
  const [loading,setLoading] = useState(false)

  useEffect(() => {
    const fetchEvents = async () => {
      setLoading(true)
      const res = await fetch('https://eonet.sci.gsfc.nasa.gov/api/v2.1/events')
      const {events} = await res.json()

      setEventData(events)
      setLoading(false)
    }

    fetchEvents()

    console.log(eventData)
  }, [])

  return (
    <div>
      <Header />
      {!loading ? <Map eventData={eventData} /> : <LoaderSpinner />}
    </div>
  );
}

export default App;

Enter fullscreen mode Exit fullscreen mode

LoaderSpinner is a separate component that uses the react-loader-spinner package. According to the documentation you'll need to manually load in the CSS. I chose the ThreeDots type variant because I thought it looked the most professional.

import React from 'react'
import Loader from 'react-loader-spinner'
import 'react-loader-spinner/dist/loader/css/react-spinner-loader.css'

const LoaderSpinner = () => {
  return (
    <div className='loader-spinner'>
      <Loader 
        type="ThreeDots"
        color="#000000"
        height={100}
        width={100}
      />
      <h1>Fetching Fire Data...</h1>
    </div>
  )
}

export default LoaderSpinner
Enter fullscreen mode Exit fullscreen mode

In the Map component, we use GoogleMapReact to render a Google Map. You'll need to give the map component a center point in coordinates, a zoom level and your API key. Mine is stored in a .env file. I also gave the center prop a set of defaultProps with the coordinates.

The Google Map component is pretty neat because you can give it children and if the children have lat and lng props the map will put them in the right place on the map.

We also provide an onClick handler to the LocationMarker component so that when a fire icon is clicked we set the locationInfo state to an object with data relevant to the fire.

import React,{useState} from 'react'
import GoogleMapReact from 'google-map-react'
import LocationMarker from './LocationMarker'
import LocationInfoBox from './LocationInfoBox'

const Map = ({eventData,center,zoom}) => {
  const [locationInfo,setLocationInfo] = useState(null)

  const markers = eventData.map(ev => {
    if (ev.categories[0].id === 8) {
      return (
        <LocationMarker 
          key={ev.id} 
          lat={ev.geometries[0].coordinates[1]} 
          lng={ev.geometries[0].coordinates[0]} 
          onClick={() => {setLocationInfo({
            id: ev.id,
            title: ev.title,
            lat: ev.geometries[0].coordinates[1],
            long: ev.geometries[0].coordinates[0]
          })}}
        />)
    }
    return null
  })

  return (
    <div className='map'>
      <GoogleMapReact
        bootstrapURLKeys={{key: process.env.REACT_APP_GOOGLE_API_KEY}}
        defaultCenter={center}
        defaultZoom={zoom}
      >
        {markers}
      </GoogleMapReact>
      {locationInfo && <LocationInfoBox info={locationInfo} />}
    </div>
  )
}

Map.defaultProps = {
  center: {
    lat: 42.3265,
    lng: -122.8756
  },
  zoom: 6
}

export default Map
Enter fullscreen mode Exit fullscreen mode

This is the kind of project I love because it has immediate real world application. Hope you like it!

Discussion (1)

pic
Editor guide
Collapse
adildeshmukh1 profile image
Adil

Suggest a path or learning resources for developing a very complex form using react hook or any other library.