【问题标题】:cannot access deep nested objects in fetch response in react无法在反应中的获取响应中访问深层嵌套对象
【发布时间】:2021-03-21 10:45:41
【问题描述】:

所以我在 Stack 和 Web 上偶然发现了很多示例,其中从异步 fetch 调用访问深层嵌套对象返回未定义。其他文章的很多答案都解决了导致访问对象和数组的方式。其他人声称这是异步操作的原因。不过,我真的无法理解它。

这是数据:

base: "stations"
clouds: {all: 1}
cod: 200
coord: {lon: -81.38, lat: 28.54}
dt: 1607561322
id: 4167147
main: {temp: 51.28, feels_like: 45.97, temp_min: 48.99, temp_max: 53.6, pressure: 1021, …}
name: "Orlando"
sys: {type: 1, id: 5234, country: "US", sunrise: 1607515628, sunset: 1607552963}
timezone: -18000
visibility: 10000
weather: [{…}]
wind: {speed: 4.52, deg: 271}

这是代码,注意useEffect回调中的setWeatherData

function WeatherDisplay(props){
  const [weatherData, setWeatherData] = useState({})

  useEffect(() => {
    fetch(`http://api.openweathermap.org/data/2.5/weather?q=Orlando&units=imperial&appid=3abd9c2df6a249e8abcf4f812de0a627`)
    .then(res => res.json())
    .then(data => {
      setWeatherData({
        data,
        name: data.name,
        main: data.main,
        ...data.main
      })
    })
    .catch(err => console.log(err))
  }, [])


  return(
    <>
      <Media style={{backgroundColor: "gray", borderRadius: "5px", height: "5.5rem"}}>
        <IconContext.Provider value={{size: "5rem", style:{fontWeight: "200"}, className:"align-self-center"}}>
          <TiWeatherPartlySunny />
        </IconContext.Provider>
          {console.log(weatherData)}
          {console.log(weatherData.name)}
          {console.log(weatherData.main)}
          {console.log(weatherData.temp)}
      </Media>
    </>
  )
}

这就是开始的方式 首先我只是将天气数据设置为数据,因为我可以渲染weatherData.name(奥兰多),但由于某种原因weatherData.main.temp返回错误,因为weatherData.main导致未定义。我四处询问,他们说这是因为承诺而且它是异步的,所以我必须使用条件等等,但这仍然不能解释它如何能够访问weatherData.name。 weatherData.clouds 和 .sys 也是如此

我继续并只是传播了我想要的对象的值,但我可以想到一些简单的情况,我的解决方法不会有用。

我想知道这是否是 react 保存深度嵌套对象的值的方式,但我真的不知道。

【问题讨论】:

    标签: javascript reactjs fetch openweathermap


    【解决方案1】:

    如果你设置如下

    setWeatherData({
        data
    })
    

    您的天气数据将是

    {
        data: {
            main: {...},
            name: '...'
            sys: {...}
        }
    }
    

    要访问 main,您应该使用

    weatherData.data.main
    

    【讨论】:

    • 如果我理解正确,您的问题是您成功调用了一个API,但在API 结果中发现main 字段未定义,而name 和sys 和clouds 字段不为空。如果是,您应该处理 API 返回空的情况并尝试再次调用它,直到您获得该值。如果没有,您能告诉我们您遇到了什么错误吗?
    • 所有字段都在那里。它们都不是 null 或空的。但是,我只能访问/呈现名称字段。在 fetch 调用的 then 回调中。我可以轻松访问任何字段,只是不在渲染中。
    【解决方案2】:

    是的,这是因为异步行为。 weatherData 对象将始终存在(最初是 {},然后在请求完成后与获取的数据一起存在)。

    在初始渲染中,weatherData.name 将等于 {}.name,这将返回 undefined,但不会导致错误。

    但是,当您运行 weatherData.main.temp 时,它将等于 {}.main.temp,这意味着您实际上是在调用 undefined.temp,这将引发错误。仅当未定义 main 属性时才会抛出此错误,这意味着一旦实际获取数据,它应该可以正常工作。

    你可以通过几种不同的方式解决这个问题,我推荐以下两种方法之一:

    1. 如果提取尚未完成,则呈现“正在加载数据...”等的条件渲染。

    2. 条件访问器。尝试访问weatherData.main?.temp 而不是weatherData.main.temp。不确定它是否可以在 JSX 内部工作,但它应该可以在外部工作,假设您使用的是最新版本的 babel,它将正确地转换条件分支。

    3. 您还可以创建一个初始的weatherData 对象,并定义了预期的接口,但所有值都设置为undefined

    换句话说,

    const initialWeatherData = {
      name: undefined,
      main: {
        temp: undefined,
      }
    }
    // etc, leaving out most of the object as I'm sure you get what I'm trying to do
    // just make sure you define the entire interface
    
    const [weatherData, setWeatherData] = useState(initalWeatherData);
    

    【讨论】:

    • {}.name 没有返回 undefined,它返回了“Orlando”,您可以在 console.log 图片中轻松看到。
    • 它在初始渲染时没有返回undefined 吗?控制台日志中应该有四个undefined。然后在第二次渲染中,您将获得粘贴在问题中的输出。
    • 啊,我明白了。是的,它不起作用的原因是因为在第一次渲染中,在进入第二次渲染之前抛出了一个错误。谢谢
    • “?”完美地为我工作。谢谢。我要搜索那个符号在 JS 中的含义。
    • @ChristianErick 很高兴听到一些成功的消息! ?. 语法称为可选链接。你可以在这里阅读更多内容developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
    【解决方案3】:

    您可以通过此代码和 API 图像来接受这个想法。希望对你有帮助

    import React  from 'react'
    
    class GetData extends React.Component {
        state = {
            data: []
    
        };
    
        async componentDidMount() {
            try {
                const url = "http://localhost:8000/blogList";
                const response = await fetch(url);
                const data = await response.json();
                console.log(data);
                this.setState({ data: data.result });
            } catch (err) {
                console.log(err);
    
            }
        }
    
        render() {
            const { data } = this.state
    
            return (
    
                <div>{
                    <ul>
                        {data.map((item, i) => {
                            return <li key={item.id}>{item.title}</li>
    
                        })}
                    </ul>
    
                }
                </div>
    
    
            );
        }
    }
    export default GetData
    

    【讨论】:

      猜你喜欢
      • 2017-01-26
      • 1970-01-01
      • 2020-12-15
      • 2020-09-02
      • 2022-11-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多