Search code examples
javascriptreactjsapireduxredux-toolkit

ERROR Cannot read properties of undefined (reading 'temp') TypeError: Cannot read properties of undefined (reading 'temp')


So this is my code (react, redux-toolkit) and I am getting that error.

import { useState, useEffect } from "react";
import { useSelector, useDispatch } from "react-redux";
import styles from "./styles.module.css";
import { getCurrentWeather } from "../../Redux/Reducers/currentWeatherSlice";
import { getUserPosition } from "../../Redux/Reducers/userPositionSlice";

// URLFor the icons
// https://openweathermap.org/img/wn/${}.pngs

function CurrentWeather() {
  const dispatch = useDispatch();
  const currentWeather = useSelector(
    (state) => state.currentWeather.currentWeather
  );
  const userPosition = useSelector((state) => state.userPosition.userPosition);

  const [query, setQuery] = useState("");
  const [x, setX] = useState(null);
  const [y, setY] = useState(null);

  //Get user's Position
  useEffect(() => {
    const successHandler = (position) => {
      setX(position.coords.latitude);
      setY(position.coords.longitude);
    };
    navigator.geolocation.getCurrentPosition(successHandler);

    if (x && y !== null) {
      dispatch(getUserPosition({ x, y }));
    }
  }, [dispatch, x, y]);

  const handleCitySearch = (e) => {
    setQuery(e.target.value);
  };

  const handleForm = (e) => {
    e.preventDefault();
  };

  const handleCityFetch = () => {
    dispatch(getCurrentWeather(query));
    setQuery("");
  };

  console.log(userPosition);

  return (
    <div className={styles.container}>
      <h1>CurrentWeather</h1>
      <div className={styles.currentWeather_container}>
        <div className={styles.input_container}>
          <form onSubmit={handleForm} className={styles.form}>
            <input
              value={query}
              type="text"
              placeholder="Search City"
              onChange={handleCitySearch}
            />
            <button onClick={handleCityFetch}>Go</button>
          </form>
        </div>

        <div className={styles.top_section}>
          {x && y && userPosition && (
            <>
              <div>
                <p>{userPosition.name}</p>
                <p>{userPosition.visibility}</p>
              </div>
              <div>
                <span>{userPosition?.main.temp}</span>
                <span>°C</span>
              </div>
            </>
          )}
        </div>
      </div>
    </div>
  );
}

export default CurrentWeather;

Even though it works as expected with the userPosition.name when I try to render userPosition.main.temp I'm getting the error.

I am not sure if its a redux state problem or that I'm trying to render before I get the data (even though it seems that I do have the data).

I've tried multiple solutions such as moving the state for the userPosition to its own slice, using the Optional Chaining operator on userPosition, also I had a bunch of console logs everywhere but I can't find my mistake.


Solution

  • You've placed the null-check on the wrong object. The error is informing you that userPosition.main is undefined. This access is fine though, same as userPosition.name and userPosition.visibility. No error is thrown since userPosition is defined. The issue arises when userPosition.main is undefined and the code attempts to access the temp property

    {x && y && userPosition && (
      <>
        <div>
          <p>{userPosition.name}</p>       // ok, value is undefined
          <p>{userPosition.visibility}</p> // ok, value is undefined
        </div>
        <div>
          <span>
            {userPosition?.main.temp}  // not ok, accessing undefined object
          </span>
          <span>°C</span>
        </div>
      </>
    )}
    

    Since the code has already checked above that to ensure userPosition is truthy, move the null-check onto the potentially null/undefined main property.

    {x && y && userPosition && (
      <>
        <div>
          <p>{userPosition.name}</p>       // ok, value is undefined
          <p>{userPosition.visibility}</p> // ok, value is undefined
        </div>
        <div>
          <span>
            {userPosition.main?.temp}  // ok, value is undefined or temp
          </span>
          <span>°C</span>
        </div>
      </>
    )}