使用 Ajax 在 React 中打开天气数据
Posted
技术标签:
【中文标题】使用 Ajax 在 React 中打开天气数据【英文标题】:Open Weather data in React using Ajax 【发布时间】:2015-12-30 02:56:58 【问题描述】:鉴于Open Weather Map current weather data API,我正在尝试使用 ajax 将当前天气数据拉入我的 React.js 应用程序,提取给定城市的当前温度值,然后在我的组件中呈现该值。
我正在使用的测试 JSON 数据位于以下网址: http://api.openweathermap.org/data/2.5/weather?id=5391997&units=imperial
var CityGrid = React.createClass(
componentDidMount: function()
$.ajax(
url: 'http://api.openweathermap.org/data/2.5/weather?id=5391997',
// ^^ this should get a variable where id=5391997 is set
dataType: 'json',
success: function(data)
this.setState(temp: data.main.temp);
.bind(this),
error: function(xhr, status, err)
console.error(this.props.url, status, err.toString());
.bind(this)
);
,
getInitialState:function()
return
cities:[
name: "San Francisco",
id: 5391997,
temp: 50, // << this should receive value from ajax call
UTCOffset:-7,
address: 999 Nathan Lane,
phone: 555-5555
,
// 12 more city objects in this array, removed for brevity
]
,
render: function()
console.log(this.state.temp); // << this returns the right temp
// for San Francisco, because I hardcoded the value into the url
return(
<div className="city-grid">
this.state.cities.map(function(city,i)
return(
<CityRow key=i name=city.name temp=city.temp
UTCOffset=city.UTCOffset address=city.address
phone=city.phone/>
);
)
</div>
);
);
module.exports = CityGrid;
我的问题:
-
如何提取温度值?在我的渲染函数中,console.log 返回 JSON 对象,这意味着数据已经绑定,可以在我的渲染函数中访问。但是,当我尝试获取温度时,我希望它类似于
this.state.data.main.temp
,我收到“数据未定义”的错误。然后,我希望能够在我的城市对象中为这 12 个城市中的每一个设置这个值:id: 5391997,
。
更新 ^^ 这已解决:@dkurbz 建议在我的 ajax 成功方法中将状态设置为 temp 对我来说很好。
-
我还面临如何为每个城市设置唯一的 url 的挑战。在我的 ajax 调用中,有
id=5391997
,我想从城市对象中获取它并将我的 ajax url 更改为类似'baseURl' + this.props.id + '&units=imperial'。我完全不知道如何做到这一点。
更新 ^^这是我目前卡住的地方。
【问题讨论】:
你能发布那个console.log的结果吗?你在哪一行得到错误? 当然,在我的渲染函数中是console.log(this.state.data.main.temp),我的控制台显示“Uncaught TypeError: Cannot read property 'main' of undefined” 可能是因为您没有在初始状态中设置数据。在ajax回来之前,this.state.data是未定义的。 您是否尝试过我发布的代码?因为我只是在 jsfiddle 中运行它,而且效果很好。 【参考方案1】:在你之前setState
data
,this.state.data
是未定义的。您可以通过在定义之前不从 this.state.data
渲染任何内容来解决此问题,或者在您的 getInitialState
中设置 data:
。
【讨论】:
好的,我已经在getInitialState
函数中的我的城市数组上方实例化了 data:
。现在我在渲染函数中的 console.log 只会到this.state.data.main
。当我尝试记录 this.state.data.main.temp
时,我得到相同的“Uncaught TypeError: Cannot read property 'temp' of undefined”错误。
正确,因为此时 this.state.data.main
也未定义。因此,您可以将 getInitialState
设置为 data: main: temp: 0
或检查它是否已定义:if (this.state.data.main) console.log(this.state.data.main.temp);
但是从 ajax 调用我只是以一种有意义的方式设置状态,而不一定是它的返回方式。即仅setState( temp: data.main.temp )
,然后仅渲染this.state.temp
。
谢谢,进步很大。但似乎我不能将渲染函数中的值用作temp=this.state.temp
,这可能是因为我如何为每个城市映射this.state.cities.map(function(city,i) ......
。我仍然感觉很困。
好吧,退后一步,组件应该渲染什么? 12个不同城市的温度?如果是这样,我将遍历每一个并将其临时条目添加到状态中。像这样gist.github.com/djkirby/f04ff0d8d044694cbec7【参考方案2】:
这可能有一些错误,但我认为它应该让你非常接近。
var React = require("react");
var $ = require("jquery");
var City = React.createClass(
propTypes:
id: React.PropTypes.string.isRequired,
units: React.PropTypes.string
,
getInitialState: function ()
return
data: ,
fetching: false
;
,
getDefaultProps: function ()
return
units: "imperial"
;
,
render: function ()
return (
<div class="city">
this.state.fetching ? "Downloading data..." : this.state.data.main.temp
</div>
);
,
componentWillMount: function ()
$.ajax(
url: "http://api.openweathermap.org/data/2.5/weather?id="+this.props.id+"&units="+this.props.units,
dataType: "json",
beforeSend: function ()
this.setState(fetching: true);
,
success: function (data)
this.setState(data: data);
,
error: function (xhr, status, err)
console.error(xhr, status, err.toString());
,
complete: function ()
this.setState(fetching: false);
,
context: this
);
);
var CityGrid = React.createClass(
propTypes:
cityIds: React.PropTypes.array.isRequired
,
renderCity: function (cityId)
return <City id=cityId />;
,
render: function ()
return (
<div class="city-grid">
this.props.cityIds.map(this.renderCity)
</div>
);
);
话虽如此...这不是正确的解决方案。应该将 ajax 调用移到组件之外(您是否查看过 Flux 或其他可以为您提供模型或存储概念的库?),然后应将返回的“数据”转换/规范化为平面以某种方式构建结构,然后作为道具传递给 City 组件(并且只有有意义/您关心的道具)。这样,City 组件就可以不知道其数据的来源。从理论上讲,您应该能够使用来自其他来源、多个来源、虚拟数据等的一些数据来渲染城市。但我不会去为您编写所有这些代码;)
【讨论】:
感谢您的详细回复!我想知道,如何在 url 中使用城市 ID?我看不到 cityIds 数组(看起来像var cityIds = [5391997, 5809844, 4853799, ...]
的位置。此外,我的 12 个城市对象中的每一个都有 6 个属性,看起来像这样:cities: [ name, temp, weather-icon, UTCOffset, address, url, phone, callphone ]
。我正在尝试找到一种方法让您的代码在其中工作我的。
您向 CityGrid 组件传递一个 cityId 数组。 CityGrid 渲染每个城市,并为城市传递一个 id。 City 使用该 ID 进行 ajax 调用。一旦你得到这个工作,你可以将额外的元数据(名称,天气图标等)添加到每个城市对象中(所以它最终会成为一个城市对象数组,不仅仅是一个城市 ID 的数字数组,而是开始简单)。这段代码到底有什么问题?
我收到错误消息:"_ 警告:失败的 propType:必需的 prop cityIds
未在 CityGrid
._` 以及渲染函数中的 Uncaught TypeError: Cannot read property 'map' of undefined
中指定。所以我我想知道 cityIds 数组的去向以及每个城市对象如何接收 Id。然后我还想知道为什么您将它们呈现为 this.props.cityIds.map(this.renderCity)
以及它与我的原始状态设置 this.state.cities.map(function(city,i) return( <CityRow key=i temp=city.temp/> ); )
相比如何
这个错误是不言自明的,不是吗?您必须将道具“cityIds”传递给组件“CityGrid”......这是一个非常基本和核心的 React 概念。至于地图功能,它们是等价的,所以我不太明白这个问题? (实际上,我的钥匙丢失了,它可能应该有)以上是关于使用 Ajax 在 React 中打开天气数据的主要内容,如果未能解决你的问题,请参考以下文章