Problem creating weather app with react.js

Hello Everyone !

I’m creating a weather website using react.js and openweathermap api. The api is fetched successfully but there is a huge problem when I try to access the data inside it. The code is

import React, { useState, useEffect } from "react";

import Weather from "./Weather";

function Main() {
  const [getCity, setGetCity] = useState("bahawalpur");
  const [city, setCity] = useState("bahawalpur");
  const [data, setData] = useState({});

  const apiUrl = `https://api.openweathermap.org/data/2.5/weather?q=${city}&units=metric&appid=07f2a451090c5d804494d164f12a4024`;

  useEffect(() => {
    fetch(apiUrl)
      .then((res) => res.json())
      .then((data) => setData(data));
  }, [apiUrl]);

  const handleOnChange = (event) => {
    setGetCity(event.target.value);
  };

  const cityChanged = () => {
    setCity(getCity);
    console.log(data.name);
  };

  return (
    <div className="main">
      <div className="container-1">
        <input
          className="inputField"
          type="text"
          placeholder="Enter your city"
          onChange={handleOnChange}
        />
        <button className="submitButton" type="submit" onClick={cityChanged}>
          Submit
        </button>
      </div>
      <div className="container-2">
        {" "}
        <p>
          {" "}
          <strong>{data.weather[0].main}</strong> // At this line when I call the main  in weather object, it shows error
        </p>
      </div>
    </div>
  );
}

export default Main;

The error is Uncaught TypeError: Cannot read properties of undefined (reading '0')

The api gives this responce

{
  "coord": {
    "lon": -122.08,
    "lat": 37.39
  },
  "weather": [
    {
      "id": 800,
      "main": "Clear",
      "description": "clear sky",
      "icon": "01d"
    }
  ],
  "base": "stations",
  "main": {
    "temp": 282.55,
    "feels_like": 281.86,
    "temp_min": 280.37,
    "temp_max": 284.26,
    "pressure": 1023,
    "humidity": 100
  },
  "visibility": 10000,
  "wind": {
    "speed": 1.5,
    "deg": 350
  },
  "clouds": {
    "all": 1
  },
  "dt": 1560350645,
  "sys": {
    "type": 1,
    "id": 5122,
    "message": 0.0139,
    "country": "US",
    "sunrise": 1560343627,
    "sunset": 1560396563
  },
  "timezone": -25200,
  "id": 420006353,
  "name": "Mountain View",
  "cod": 200
  }          

I’ve tried copying code from many sources but nothing works. I know I’m making a huge mistake here.

So, that is saying that you are trying to read the property of “0” (sounds like an array) off something that is undefined. The only place that could be is here:

          <strong>{data.weather[0].main}</strong> // At this line when I call the main  in weather object, it shows error

So, data.weather is undefined at some point.

You initialize data with:

const [data, setData] = useState({});

So, in the beginning, data.weather is definitely undefined. I don’t see any protection there so I would expect to get that error on the first render.

Try putting:

console.log(data.weather)

right before the return.

If your data is going to start out incomplete (nothing wrong with that) then your UI needs to be able to handle that.

1 Like

Thanks Kevin,
Nothing wrong when I put console.log(data.weather) or even console.log(data.weather[0].main). It shown error when rendering it in JSX, how to fix this?

What does it say? I don’t know what “nothing wrong” means.

In any case, what happens if you remove that line in the JSX? What happens if you change it to:

<strong>{data.weather && data.weather[0].main}</strong>

or

<strong>{JSON.stringify(data.weather)}</strong>

To be a good coder, you MUST be a good debugger. And being a good debugger is all about being a good detective. Figure out how to isolate the issue. Start removing things, changing things, logging things… do it in a way to pinpoint exactly where, when, and under what conditions it is happening.

1 Like

Sorry for the “nothing wrong” :sweat_smile:

I meant that no error is showing and the weather object is being displayed

 "weather": [
    {
      "id": 800,
      "main": "Clear",
      "description": "clear sky",
      "icon": "01d"
    }
  ],

After removing the line from JSX, it doesn’t displays but the website works fine.

Wow finally everything is working fine, the value of main is showing in the page. I still don’t know what this syntax says.

The result is [{"id":800,"main":"Clear","description":"clear sky","icon":"01d"}] in the web page, that’s not what I want but Thank You for the solution.

Also I’m sorry I cannot give any screenshots because my windows snip and sketch is stuck somehow.

Thanks, I’m taking notes.

That means that the issue is that at some point data.weather is undefined (or at least falsy) at some point. That makes sense. The syntax is called a short circuit &&. Remember that in JS, && is not a true logical AND, it does not necessarily evaluate to a boolean. a && b is saying "if a is falsy, evaluate to a, otherwise evaluate to b. It is functionally equivalent to a == true ? b : a`. That works essentially as logical AND if you convert to boolean.

It is used above to say, “if data.weather is falsy, evaluate to that (in other words, don’t evaluate the rest of the expression) otherwise evaluate to data.weather[0].main”. It will prevent it from failing if data.weather is undefined.

A more modern way to write that would be with optional chaining:

data.weather.?[0].main

but I didn’t know if you’d be familiar with that.

The result is [{"id":800,"main":"Clear","description":"clear sky","icon":"01d"}] in the web page, that’s not what I want but Thank You for the solution.

The point wasn’t a final solution but a diagnostic tool, confirming that the data gets there.

But ultimately, you said:

Nothing wrong when I put console.log(data.weather) or even …

I think that if you look more closely, you’ll see that it first time that is logged, it is undefined. That was the point of doing that.

It was failing because data.weather was undefined on the first render. This is a common issue with async data in React. These are a few of the was to handle it.

1 Like

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.