使用 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】:

在你之前setStatedatathis.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( &lt;CityRow key=i temp=city.temp/&gt; ); ) 相比如何 这个错误是不言自明的,不是吗?您必须将道具“cityIds”传递给组件“CityGrid”......这是一个非常基本和核心的 React 概念。至于地图功能,它们是等价的,所以我不太明白这个问题? (实际上,我的钥匙丢失了,它可能应该有)

以上是关于使用 Ajax 在 React 中打开天气数据的主要内容,如果未能解决你的问题,请参考以下文章

原生js实现查询天气的小应用

jQuery Ajax应用之--天气预报

js ajax数据的获取小示例 天气信息填充表格

php怎么解析天气预报api返回的数据

三种实现AJAX的方法以及Vue和axios结合使用的坑

通用jsonp跨域技术获取天气数据