Home > Software design >  Problem about response data from Slice to index.js - React redux toolkit
Problem about response data from Slice to index.js - React redux toolkit

Time:11-15

I want to fetch data from API and trying to use in index.js

Error:

TypeError: Cannot read properties of undefined (reading 'icon')

When I console.log it prints

Empty Array of index.js > response data of weatherSlice.js > and finally response data of index.js as an array

I was getting undefined error and tried this and kinda worked .

{getCity.length !== 0 && (
<Typography variant="h6"  component="div">
 <div>Wind : {getCity.current.gust_kph} kph</div>
 <div>Pressure: {getCity.current.pressure_in} in</div>
</Typography>
                )}

But this time it gives same error on this block

{getCity.length !== 0 && (
  <Grid item xs={3} sx={{mb:3}}>
    <div  className="label">{getDate()}</div>
    <div className="label"> <img src={`${getCity.forecast.forecastday[1].condition.icon}`} alt="" /></div> // Gives undefined (reading"icon")
    <div className="label" >22 C</div> 
  </Grid>)}

Index.js

const dispatch = useDispatch();
const [selectedCity, setSelectedCity] = useState('Ankara');
const getCity  = useSelector((state) => state.weather.item);
const [datee , setDate ] = useState('');

useEffect(() => {
    dispatch(fetchDefault(selectedCity))   
    setDate(getDate())
}, [dispatch])

weatherSlice

export const fetchDefault = createAsyncThunk('weather/getWeather', async (selectedCity) => {
const res = await axios(`http://api.weatherapi.com/v1/forecast.json?key=ebb6c0feefc646f6aa6124922211211&q=${selectedCity}&days=10&aqi=no&alerts=no
`)
return res.data});

export const weatherSlice = createSlice({   
name: "weather",
initialState : {
    item : [],
},
reducers:{},
extraReducers:{
    [fetchDefault.fulfilled]: (state , action) => {
       
        state.item = action.payload;
        
        console.log(state.item)
         
    },
    [fetchDefault.pending]: (state , action) => {
       
        console.log("sadsad")
    }
}

CodePudding user response:

After the state.weather.item state is populated it's now an object, not an array. The initial condition getCity.length !== 0 works/passes because getCity.length is undefined and undefined !== 0 evaluates true. The issue is occurring after you start accessing into the state.

The fetched city data is an object with location, current, and forecast properties.

// 20211114135700
// https://api.weatherapi.com/v1/forecast.json?key=ebb6c0feefc646f6aa6124922211211&q=seattle&days=10&aqi=no&alerts=no

{
  "location": {
    "name": "Seattle",
    "region": "Washington",
    "country": "United States of America",
    "lat": 47.61,
    "lon": -122.33,
    "tz_id": "America/Los_Angeles",
    "localtime_epoch": 1636927019,
    "localtime": "2021-11-14 13:56"
  },
  "current": {
    "last_updated_epoch": 1636926300,
    "last_updated": "2021-11-14 13:45",
    "temp_c": 16.1,
    "temp_f": 61.0,
    "is_day": 1,
    "condition": {
      "text": "Light rain",
      "icon": "//cdn.weatherapi.com/weather/64x64/day/296.png",
      "code": 1183
    },
    "wind_mph": 13.6,
    "wind_kph": 22.0,
    "wind_degree": 190,
    "wind_dir": "S",
    "pressure_mb": 1014.0,
    "pressure_in": 29.94,
    "precip_mm": 1.0,
    "precip_in": 0.04,
    "humidity": 90,
    "cloud": 100,
    "feelslike_c": 16.1,
    "feelslike_f": 61.0,
    "vis_km": 3.2,
    "vis_miles": 1.0,
    "uv": 4.0,
    "gust_mph": 18.8,
    "gust_kph": 30.2
  },
  "forecast": {
    "forecastday": [
      {
        "date": "2021-11-14",
        "date_epoch": 1636848000,
        "day": {
          "maxtemp_c": 16.2,
          "maxtemp_f": 61.2,
          "mintemp_c": 11.5,
          "mintemp_f": 52.7,
          "avgtemp_c": 14.9,
          "avgtemp_f": 58.8,
          "maxwind_mph": 16.1,
          "maxwind_kph": 25.9,
          "totalprecip_mm": 21.1,
          "totalprecip_in": 0.83,
          "avgvis_km": 9.3,
          "avgvis_miles": 5.0,
          "avghumidity": 93.0,
          "daily_will_it_rain": 1,
          "daily_chance_of_rain": 99,
          "daily_will_it_snow": 0,
          "daily_chance_of_snow": 0,
          "condition": {
            "text": "Heavy rain",
            "icon": "//cdn.weatherapi.com/weather/64x64/day/308.png",
            "code": 1195
          },
          "uv": 1.0
        },
        "astro": {
          ...
        },
        "hour": [
          ...
        ]
      },
      ...
    ]
  }
}

You are attempting to render the forecast, but here's where the code really goes sideways. You're assuming there's at least 2 elements (i.e. the getCity.forecast.forecastday.length>= 2), and then if there is, assume theres aconditionproperty. When there isn't andgetCity.forecast.forecastday[1].condition` is undefined, this is the error you are seeing.

From what I can tell, the condition property is nested within a day field. Since it's unclear what properties are guaranteed to exist in the response data your best bet is to:

  1. First make sure you are accessing into the correct path
  2. Use null-checks/guard-clauses or Optional Chaining operator to prevent accidental null/undefined accesses

The updated object property path is as follows:

getCity.forecast.forecastday.[1].day.condition.icon

If any of these are potentially undefined or otherwise not returned in the data, the corrected access using the Optional Chaining operator is as follows:

getCity.forecast?.forecastday?.[1]?.day?.condition?.icon

Which is the equivalent null-check/guard-clause version of:

getCity.forecast 
  && getCity.forecast.forecastday
  && getCity.forecast.forecastday[1]
  && getCity.forecast.forecastday[1].day
  && getCity.forecast.forecastday[1].day.condition
  && getCity.forecast.forecastday[1].day.condition.icon

Use the same sort of check for the current weather data:

{getCity.current && (
  <Typography variant="h6" component="div">
    <div>Wind : {getCity.current.gust_kph} kph</div>
    <div>Pressure: {getCity.current.pressure_in} in</div>
  </Typography>
)}

Finally, update the initial state for the weather slice to match the data invariant, it should be an object.

initialState : {
  item : {},
},
  • Related