我很难将嵌套对象呈现到reactjs页面上
import React, { Component } from "react";
import Toolpanel from "./Todopanel";
import Toollist from "./Toollist";
class App extends Component {
constructor(props) {
super(props);
this.state = {
users: [],
city: "Auckland",
cityWeather: {}
};
this.updateUser = this.updateUser.bind(this);
}
updateUser(entry) {
console.log(entry);
let item = {
text: entry,
key: Date.now()
};
this.setState(prevstate => {
return {
users: prevstate.users.concat(item)
};
});
}
componentDidMount() {
let apiId = "***************************";
let city = this.state.city;
let ApiString =
"http://api.openweathermap.org/data/2.5/weather?q=" +
city +
"&APPID=" +
apiId;
fetch(ApiString)
.then(results => results.json())
.then(data => this.setState({ cityWeather: data }));
}
render() {
let test = this.state.cityWeather;
return (
<div>
<Toolpanel parentUpdate={this.updateUser} />
<div>wind speed : {test.wind.speed} </div>
</div>
);
}
}
export default App;
我已经添加了从天气API接收到的JSON文件
//Json file
{
"coord": { "lon": 174.77, "lat": -36.85 },
"weather": [
{
"id": 804,
"main": "Clouds",
"description": "overcast clouds",
"icon": "04n"
}
],
"base": "stations",
"main": {
"temp": 293.7,
"pressure": 1018,
"humidity": 77,
"temp_min": 293.15,
"temp_max": 294.26
},
"visibility": 10000,
"wind": { "speed": 5.1, "deg": 360 },
"clouds": { "all": 92 },
"dt": 1553672420,
"sys": {
"type": 1,
"id": 7345,
"message": 0.0043,
"country": "NZ",
"sunrise": 1553624951,
"sunset": 1553667823
},
"id": 2193733,
"name": "Auckland",
"cod": 200
}
我正在尝试将JSON的风速呈现给我的页面..但是向我抛出一条错误消息,提示“ TypeError:无法读取未定义的属性'speed'” ...我对ReactJ相当陌生。
答案 0 :(得分:3)
如果您看代码,下面是事件的顺序:
constructor
componentDidMount
componentDidMount
启动async
请求以获取数据,然后将其解析并设置为状态。render
方法尝试从状态读取数据。现在,由于#3中的请求是异步请求,因此在第一次调用render
方法时,它可能未及时完成。
因此,您需要检查您的请求是否已完成或失败或正在运行。
您可以使用它conditionally render渲染方法中的内容。
推荐阅读 async rendering with examples of when data is fetched from an external resource
上的官方reactjs博客条目答案 1 :(得分:2)
您没有错。您收到的错误是因为您正在执行的抓取操作需要花费一些时间,并且渲染首先执行而没有填充数据。
因此,它第一次在您的渲染方法中获得test = {}
的值。因此test.wind.speed
将引发错误。
相反,显示某种加载状态或仅显示return null
,直到执行调用为止:
render() {
let test = this.state.cityWeather;
if (!test) {
return 'Loading...';
}
....
}
答案 2 :(得分:1)
由于fetch
是异步调用,因此您访问属性的速度太快,这会花费一些时间,但是您的render
会在此之前触发。
像这样使用它
{ test && <div>wind speed : {test.wind.speed} </div>}
答案 3 :(得分:1)
最初,您的测试将为null,因为您尚未收到来自API的任何响应,因此您应在使用前检查变量是否存在。因此,只需像使用它之前检查它是否存在:
render() {
let test = this.state.cityWeather;
return (
<div>
<Toolpanel parentUpdate={this.updateUser} />
<div>wind speed : {test && test.wind && test.wind.speed ? test.wind.speed : ''} </div>
</div>
);
}
答案 4 :(得分:1)
由于您没有发布ToolPanel
组件实现,因此我可能是错的(我缺少一些信息)。但是,我也很确定您的问题没有loading
变量。
基本上,第一次调用render()
方法时,您有this.state.cityWeather
是一个空对象{}
;那是因为您获取了componentDidMount()
中的数据。因此,第一次调用render()
时,this.state.cityWeather
为空,您无法访问this.state.cityWeather.wind.speed
,因为您在wind
中没有属性this.state.cityWeather
! / p>
因此,通常,执行此操作的常用方法是在状态中添加属性loading
,然后在true
中将其设置为constructor
。然后,在提取的回调中,在this.state.cityWeather
中设置数据的同时,还将loading
设置为true
。
最后,在render()
方法中编写了条件渲染:如果this.state.loading === true
,则打印一个简单的段落,如<p>I'm retrieving info!</p>
,否则,如果this.state.loading === false
,则可以渲染想要。