开发者问题收集

获取数据,获取对象,但仍有错误。未捕获(在承诺中)TypeError:无法读取未定义的属性(读取“0”)

2022-09-03
819

无法修复此错误。 我通过 fetch 方法从 thingspeak.com 接收数据(对象)。然后我想从该对象呈现三个值:名称、温度和时间。我可以看到温度和名称,但看不到时间。 这是我在控制台中的错误: 未捕获(在承诺中)TypeError:无法读取未定义的属性(读取“0”)。 有什么想法吗?

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

在此处输入图片说明

1个回答

在使用 setChannelInfo(data); 设置新状态后立即调用 timeConverter 将引发异常,因为 1) 初始 channelInfo 值为 {},因此没有 .feeds[0].created_at 和 2) 调用 setChannelInfo 不会立即更新变量。它只会在下次渲染时更新。

您可以切换到 useMemo ,添加 undefined 检查,将 channelInfo 的初始状态更改为未定义。

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;
Sergey Sosunov
2022-09-03