Home > Enterprise >  Fetching data, get object, but still have error. Uncaught (in promise) TypeError: Cannot read proper
Fetching data, get object, but still have error. Uncaught (in promise) TypeError: Cannot read proper

Time:09-04

Cannot fix this error. I receive data (object) from thingspeak.com via fetch method. Then I want to render three values from that object: name, temperature and time. I can see temperature and name but not time. Here is my error in console: Uncaught (in promise) TypeError: Cannot read properties of undefined (reading '0'). Any ideas?

import React, { useState, useEffect } from 'react'

const App = () => {

  const [channelInfo, setChannelInfo] = useState({});
  const [isLoading, setIsLoading] = useState(true);
  const [dateWithOffset, setDateWithOffset] = useState(null);

  const getThermoData = async () => {
    setIsLoading(true);
    const response = await fetch(`https://api.thingspeak.com/channels/618304/fields/1.json?results=1`);
    const data = await response.json();
    setChannelInfo(data);
    setIsLoading(false);
    timeConverter();
  }

  const timeConverter = () => {
    const channelDate = channelInfo.feeds[0].created_at;
    const date = new Date(channelDate);
    const timestampWithOffset = date.getTime();
    setDateWithOffset(new Date(timestampWithOffset));
  }

  useEffect(() => {
    getThermoData();
  }, [])

  return (
    <div className='card'>
      {
        isLoading ? <p className='loading'>Loading...</p> : <>
          <h5 className='channel-name no-select'>{channelInfo.channel.name}</h5>
          <p className='temperature-value no-select'>{channelInfo.feeds[0].field1}</p>
          <h5 className='channel-time no-select'>{dateWithOffset}</h5>
        </>
      }
    </div>
  )
}

export default App

enter image description here

CodePudding user response:

Calling timeConverter just after setting the new state with setChannelInfo(data); will throw you an exception due to 1) Initial channelInfo value is {} so there is no .feeds[0].created_at and 2) calling setChannelInfo will not update the variable immediately. It will be updated on next render only.

You can switch to useMemo, add undefined check, change initial state of channelInfo to undefined.

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

const App = () => {
  const [channelInfo, setChannelInfo] = useState();
  const [isLoading, setIsLoading] = useState(true);
  const dateWithOffset = useMemo(() => {
    if (!channelInfo) return "";

    const channelDate = channelInfo.feeds[0].created_at;
    const date = new Date(channelDate);
    const timestampWithOffset = date.getTime();
    return new Date(timestampWithOffset).toString();
  }, [channelInfo]);

  const getThermoData = async () => {
    setIsLoading(true);
    const response = await fetch(
      `https://api.thingspeak.com/channels/618304/fields/1.json?results=1`
    );
    const data = await response.json();
    setChannelInfo(data);
    setIsLoading(false);
  };

  useEffect(() => {
    getThermoData();
  }, []);

  return (
    <div className="card">
      {isLoading ? (
        <p className="loading">Loading...</p>
      ) : (
        <>
          <h5 className="channel-name no-select">{channelInfo.channel.name}</h5>
          <p className="temperature-value no-select">
            {channelInfo.feeds[0].field1}
          </p>
          <h5 className="channel-time no-select">{dateWithOffset}</h5>
        </>
      )}
    </div>
  );
};

export default App;
  • Related