Home > Software design >  Simple weather app breaking at weather.main.temp variable
Simple weather app breaking at weather.main.temp variable

Time:02-11

I'm building a really basic weather app with React hooks, codesandbox.io and OpenWeatherAPI. It's breaking at const temp = forecast.main.temp; and returning "TypeError: Cannot read properties of undefined (reading 'temp')" It actually does run when I initially write it but breaks if I add another variable or have to edit the temp variable in any way.

import React, { useState } from "react";
import "../styles.css";
import CityCard from "./cityCard";

export default function GetWeather() {

  const [city, setCity] = useState('');
  const [forecast, setForecast] = useState([]);

  const getCity = async (e) => {
    e.preventDefault();

  //API variables 
  const url = `https://api.openweathermap.org/data/2.5/weather?q=${city}&units=imperial&appid=${APIkey}`;
  
  //fetch response
  try {
  const res = await fetch(url);
  const data = await res.json();
  setForecast(data);
  } catch (err) {
    console.error(err);
  }

};

  return (
    //basic input form to search by city
    <div>
      <h1 className="title">Weather App</h1>
      <CityCard forecast={forecast} />
      <form className="form" onSubmit={getCity}>
      <label className="label" htmlFor="city">
      <p>Search by City</p>
      </label>
      <input 
        className="input" 
        type="text" 
        name="query place"
        placeholder="i.e. Seattle"
        value={city} onChange={(e) => setCity(e.target.value)}
        >
      </input>
      <button 
      className="button" 
      type="submit"
      >Search</button>
      </form>
    </div>
  );
}

CityCard

import React from "react";
import "../../src/styles.css";

export default function CityCard({ forecast }) {
  //pass props to cards
  const cityName = forecast.name;
  const temp = forecast.main.temp;

  return (
      <div className="card-container">
        <p className="card-title">{cityName}</p>
        <p>Temp: {temp} </p>
      </div>

  );
}

CodePudding user response:

Issue

The initial forecast state is declared as an array:

const [forecast, setForecast] = useState([]);

and passed to CityCard on forecast prop:

<CityCard forecast={forecast} />

then accessed as if it were an object:

function CityCard({ forecast }) {
  //pass props to cards
  const cityName = forecast.name;  // OK, undefined
  const temp = forecast.main.temp; // Not OK, can't access temp of undefined

  return (
      <div className="card-container">
        <p className="card-title">{cityName}</p>
        <p>Temp: {temp}</p>
      </div>

  );
}

Solution

Use Optional Chaining operator to protect against null/undefined property accesses.

function CityCard({ forecast }) {
  //pass props to cards
  const cityName = forecast?.name;
  const temp = forecast?.main?.temp;

  return (
      <div className="card-container">
        <p className="card-title">{cityName}</p>
        <p>Temp: {temp}</p>
      </div>

  );
}

Or wait to render CityCard when there's a valid forecast data to display.

const [forecast, setForecast] = useState();

...

{forecast?.name && forecast?.main?.temp && <CityCard forecast={forecast} />}

OpenWeather JSON API response

  • Related