Search code examples
javascriptreactjswebreact-fullstack

TypeError: Cannot read property '0' of undefined dataExtracting


I am very new to reactjs and I was making my second project on Weather Forcast APP. In which I am getting error whenever I wanted to get the data that is stored in weatherList. it is howint that " TypeError: Cannot read property '0' of undefined dataExtracting ".

Please Help me with right suggestions that I should use to avoid this error.

Following is my App.js Code :-

import React, { useEffect, useState} from "react";
import './App.css';
import SearchBar from './components/SearchBar/SearchBar';
import WeatherBox from './components/WeatherCard/WeatherBody';
import { Grid } from "@material-ui/core";

import { makeStyles } from '@material-ui/core/styles';

require('dotenv').config();  


const useStyles = makeStyles({
  root: {
    minWidth: 275,
    backgroundColor: '#091f43',
    color: 'var(--text_light)',
    margin: 'auto'
  },
  inputs: {
      border: 'none',
      background: 'none',
      outline: 'none',
      color: 'inherit',
      fontSize: '2rem',
      height: '40px',
      padding: '5px 5px 10px',
      borderBottom: '1px solid'
  },
  buttons: {
      border: 'none',
      outline: 'none',
      color: 'inherit',
      fontSize: '1rem',
      fontWeight: 'bold',
      letterSpacing: '0.1em',
      padding: '15px 20px',
      marginLeft: '15px',
      borderRadius: '5px',
      backgroundColor: 'red',
      transition: 'background 0.3s ease-in-out',
      cursor:'pointer'
  },
  formStyling: {
      position: 'relative',
      display: 'flex',
      alignItems: 'center',
  },
  headings: {
      fontWeight: 'bold',
      fontSize: '4rem',
      letterSpacing: '0.02em',
      padding: '0 0 30px 0'
  }
});


const API_KEY = process.env.REACT_APP_BART_API_KEY;

function App() {

  const [city, setCity] = useState(null);
  const [responseData, setresponseData] = useState(null);
  const [searches, setSearches] = useState(null);
  const [weatherList, setweatherList] = useState([]);
  const [date, setdate] = useState(null);
  // const [buttonClick, setButtonClick] = useState(false);

  const classes = useStyles();
  const isRowBased = window.matchMedia('(min-width: 700px)');

  useEffect( () => {
    const fetchApi = async () => {
      const url = `https://api.openweathermap.org/data/2.5/forecast?q=${searches}&appid=${API_KEY}`;
      const response = await fetch(url);
      // console.log(response);
      const resJson = await response.json();
      setresponseData(resJson);
      setweatherList(resJson.list);
    };

    fetchApi();
  }, [searches])
  
  function dataExtracting()
  {
    var dates = weatherList[0].dt_txt;
    setdate(dates);
  }
  function handleChange(event) {
    const cityName = event.target.value;
    setCity(cityName);
  }

  function submitCity(event) {
    setSearches(city);

      dataExtracting();
    
    // setButtonClick(true);
    // setTimeout( () => setButtonClick(false), 2000);
    event.preventDefault();
  }

  return (
    <div className="App">
      <Grid className={classes.root} sm={6}>
        <h1 className={classes.headings}>Weather Forcast App</h1>
        <form className={classes.formStyling} style={styles.container(isRowBased)}>
            <input onChange={handleChange} className={classes.inputs} style={styles.containerInput(isRowBased)} type="text" placeholder="Search for a city" autoFocus />
            </form>

            <button className={classes.buttons} style={styles.containerButton(isRowBased)} type="submit" onClick={submitCity}>Search</button>
            <span class="msg"></span>
        
      </Grid>
      <WeatherBox />    
    </div>
  );
}

const styles = {
  container: isRowBased => ({
      flexDirection: 'column',
    width: '100%'
  }),
  containerInput: isRowBased=> ({
      width: '100%'
  }),
  containerButton: isRowBased => ({
      margin: '20px 0 0 0',
      width: '100%'
  })
};

export default App;

This is Error I am getting :-

TypeError: Cannot read property '0' of undefined
dataExtracting
P:/Web Dev/Weather-Application-Reactjs/weatherapp/src/App.js:87
  84 | 
  85 | function dataExtracting()
  86 | {
> 87 |   var dates = weatherList[0].dt_txt;
     | ^  88 |   setdate(dates);
  89 | }
  90 | function handleChange(event) {

Edit

I have checked the states in chrome inspect, I saw that the data I wanted to save in weatherList is being saved without any error, but I am not able to access it through dataExtracting() function. Actually, I need to take the list from the response and then extract 5 days of weather data to display in the web app. To do so I am using dataExtracting() function which is being called in submitCity() function. After Adding the function only I am getting this error. This edit is for clarification that there is no problem with API calling, I have checked many times.


Solution

  • I am wondering if you are trying to access the list before it has properly populated. What I mean is that your initial API call here in useEffect should be returning an error, since it looks something like this:

      useEffect( () => {
        const fetchApi = async () => {
          const url = `https://api.openweathermap.org/data/2.5/forecast?q=null&appid=<YOUR_KEY>`;
          const response = await fetch(url);
          // console.log(response);
          const resJson = await response.json();
          setresponseData(resJson);
          setweatherList(resJson.list);
        };
    

    When I perform this test using my API key my response is:

    {
        "cod": "404",
        "message": "city not found"
    }
    

    Since you are setting the initial state of city to null, this first pass shouldn't be providing any data, which would explain why your weatherList is undefined. The only idea that I have is that your submitCity function is not finishing setSearches and fulfilling the fetchApi call before you are trying to access the search list in the dataExtracting() function. Since you need to update state with the new city, then enter your async function and await the response, await the conversion, and then set the list all before entering your dataExtracting function, I believe that this might be the issue.

    A couple of solutions that might work are: add a check in your useEffect to see if there is a list. If there is, extract the data immediately and setdate. I don't like this solution, but I think it should work:

      useEffect( () => {
        const fetchApi = async () => {
          const url = `https://api.openweathermap.org/data/2.5/forecast?q=${searches}&appid=5b451f60067d169e5b9acb877efadcda`;
          const response = await fetch(url);
          // console.log(response);
          const resJson = await response.json();
          setresponseData(resJson);
          setweatherList(resJson.list);
    
          if (resJson.list && resJson.list.length) {
              setdate(resJson.list[0].dt_txt);
          }
        };
    

    If you perform the check for weatherList in your useEffect, then you can decouple the logic of setting your searches and extracting the dates inside of your submitCity (if you did add this to useEffect, you would remove the dataExtraction call from submitCity). I haven't tested this approach exactly, but I suspect that this order of events is what is giving you issues. Additionally, it might be worth considering adding checks for valid city inputs, or perhaps even converting the input to a dropdown list of valid cities to help with data integrity. I could foresee misspelled cities etc causing issues down the road otherwise.