简体   繁体   English

反应。 如何仅使用现有密钥的fetch和setState处理API响应中的缺失密钥?

[英]React. How to deal with missing keys in API response using fetch and setState only for existing keys?

I am working on a React project that use public API to fetch some data. 我正在使用公共API来获取一些数据的React项目上工作。 Problem is I found a lot of interesting and definitely highly valuable API can have some data missing. 问题是我发现很多有趣且绝对有价值的API可能会丢失一些数据。 For example, I am using waqi.info which collect information about air quality from stations all around the world. 例如,我使用的是waqi.info,它从世界各地的车站收集有关空气质量的信息。 And here is a problem - when I send requests I need values from a specific key in response JSON. 这是一个问题-当我发送请求时,我需要来自特定键的值以响应JSON。 Some stations don't collect part of data, so there is no key I am looking for in JSON. 有些工作站不收集部分数据,因此我没有在JSON中寻找密钥。 As effect I get what I expect: 结果我得到了我所期望的:

Uncaught (in promise) TypeError: Cannot read property 'v' of undefined

I need to change state only in case key exist in response, or better - set state to the given value like for example 'No data'. 我只需要在响应中存在键的情况下更改状态,或者更好-将状态设置为给定值,例如“无数据”。 I can manually check every key for 'undefined' but it is very crude and I am looking for something more smart and elegant. 我可以手动检查每个键是否为“ undefined”,但它非常粗糙,我正在寻找更智能,更优雅的产品。 Component code (stripped from most unnecessary things) is here: 组件代码(从大多数不必要的内容中删除)在这里:

class Item extends React.Component {
    constructor(){
        super();
        this.state={
            dataSourceName: null,
            dataSourceDetailsCO: null,
            dataSourceDetailsNO2: null,
            dataSourceDetailsPM10: null,
            dataSourceDetailsPM25: null,
            dataSourceDetailsSO2: null, 
            dataSourceDetailsTemp: null,
            dataSourceDetailsWind: null
        }; 
    }
    fetchStationDetails = () => {
        const stationUid = this.props.uid;
        const urlStationDetails = 'https://api.waqi.info/feed/@' + stationUid + '/?token=' + apiKey;
        fetch(urlStationDetails)
            .then(res => res.json())
            .then(json => this.setState({
                dataSourceName: json.data.attributions[0].name,
                dataSourceDetailsCO: json.data.iaqi.co.v,
                dataSourceDetailsNO2: json.data.iaqi.no2.v,
                dataSourceDetailsPM10: json.data.iaqi.pm10.v,
                dataSourceDetailsPM25: json.data.iaqi.pm25.v,
                dataSourceDetailsSO2: json.data.iaqi.so2.v, 
                dataSourceDetailsTemp: json.data.iaqi.t.v,
                dataSourceDetailsWind: json.data.iaqi.w.v
            })) 
    }
    render(){
        const dataSourceName = this.state.dataSourceName;
        return (
            <li>
                <div>
                    Id: {this.props.uid} Longitude: {this.props.lon} Latitude: {this.props.lat}
                </div>
                <div>
                    General Air Quality Index (AQI): {this.props.aqi}
                </div>
                <div>
                    <button onClick={this.fetchStationDetails}>Click to get detailed data</button>
                </div>
                {dataSourceName ? <ItemData 
                    dataSourceName={this.state.dataSourceName}
                    dataSourceDetailsCO={this.state.dataSourceDetailsCO}
                    dataSourceDetailsNO2={this.state.dataSourceDetailsNO2}
                    dataSourceDetailsPM10={this.state.dataSourceDetailsPM10}
                    dataSourceDetailsPM25={this.state.dataSourceDetailsPM25}
                    dataSourceDetailsSO2={this.state.dataSourceDetailsSO2}
                    dataSourceDetailsTemp={this.state.dataSourceDetailsTemp}
                    dataSourceDetailsWind={this.state.dataSourceDetailsWind}
                /> : null }
            </li>
        )
    }
}

Thank you in advance :) 先感谢您 :)

This is a common problem, you need always to take this into consideration, what you should try to do is parsing the JSON and checking if the nodes you are looking for are defined or create a whitelist, also there is a lot of duplication in your code you can clean and make it more clear : 这是一个常见的问题,您始终需要考虑到这一点,您应该尝试做的是解析JSON并检查您要查找的节点是否已定义或创建了白名单,而且您的重复项很多您可以清理并使其更清晰的代码:

whiteList = {
    dataSourceName:"co",
    dataSourceDetailsNO2:"no2",
    dataSourceDetailsPM10:"pm10",
    ...
    ...
}

parseData = (data) => {
    try{
        Object.entries(this.whiteList).forEach(([key, value]) => {

            this.setState({
               [key]:data.data.iaqi[value].v
            })
        })
    }catch(e){
        //handle Errors
    }
}


fetchStationDetails = () => {
    const {uid} = this.props;

    const urlStationDetails = `https://api.waqi.info/feed/@${uid}/?token=${apiKey}`;

    fetch(urlStationDetails)
        .then(res => res.json())
        .then(json => this.parseData(json)) 
        .catch(console.log)
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM