从React中的组件状态读取信息时'无法读取未定义的属性'DV'

时间:2019-10-09 15:32:30

标签: javascript reactjs

尝试从“ this.state”中的JSON对象读取信息时发生未定义的错误。

组件类:

class App extends Component {
  state = {}
    // Code is invoked after the component is mounted/inserted into the DOM tree.
    componentDidMount() {
      const url = 'http://datapoint.metoffice.gov.uk/public/data/val/wxfcs/all/json/APIKEY'

      fetch(url)
        .then(response => {return response.json()})
        .then(data => {
          this.setState(data)
        })      
    }

    render() {
      console.log(this.state.SiteRep.DV)

      return <p>TEXT</p>
    }
  }

  export default App

Json对象:

{
  "SiteRep": {
    "Wx": {
      "Param": [
        {
          "name": "FDm",
          "units": "C",
          "$": "Feels Like Day Maximum Temperature"
        },
        {
          "name": "FNm",
          "units": "C",
          "$": "Feels Like Night Minimum Temperature"
        },
        ...
      ]
    },
    "DV": {
      "dataDate": "2019-10-09T13:00:00Z",
      "type": "Forecast",
      "Location": {
        "i": "354287",
        "lat": "52.0951",
        "lon": "1.3143",
        "name": "WOODBRIDGE",
        "Period": [
          {
            "type": "Day",
            "value": "2019-10-09Z",
            "Rep": [
              {
                "D": "W",
                "Gn": "22",
                "Hn": "66",
                "PPd": "8",
                ...
              },
              {
                "D": "WSW",
                "Gm": "22",
                "Hm": "87",
                "PPn": "1"
              }
            ]
          },
          {
            "type": "Day",
            "value": "2019-10-10Z",
            "Rep": [
              {
                "D": "WSW",
                "Gn": "29",
                "Hn": "61",
                "PPd": "5",
              },
              {
                "D": "SW",
                "Gm": "34",
                "Hm": "87",
                "PPn": "19",
              }
            ]
          }
        ...
        ]
      }
    }
  }
}

我将映射“ Period”列表以映射某些元素,但是当尝试访问“ this.state”中的对象的所述部分时,遇到错误“无法读取属性” DV 'of undefined'

在状态内找到该对象,所有Json数据均正确,并且当我不在'.SiteRep'对象之外时,可以在控制台中访问它。觉得我做错了什么:D

3 个答案:

答案 0 :(得分:0)

这是生命周期问题。加载组件后ComponentDidMount触发,这意味着this.state.SiteRep.DV尚不存在。您需要添加检查以查看SitRep上是否存在state,以便不会出错。 所以...

if(this.state.hasOwnProperty('SiteRep') console.log(this.state.SiteRep.DV)

这是组件的预期行为:

First render happens 
=> `ComponentDidMount` is fired 
=> Request is made and response is set to state 
=> setState triggers another render where SiteRep does exist on state

然后使用您的JSX:

render() {
 if(this.state.SiteRep && this.state.SiteRep.DV) { 
     return <p>interpolate a value from {this.state.SiteRep.DV.someStringProp} </p>
 }
 return null
}

答案 1 :(得分:0)

这里的问题是,尽管您的Json位于componentDidMount中,但是render()发生在获取完成之前。只需在访问数据之前检查数据是否可用即可解决您的问题。

class App extends Component {
      state = {}
        // Code is invoked after the component is mounted/inserted into the DOM tree.
        componentDidMount() {
          const url = 'http://datapoint.metoffice.gov.uk/public/data/val/wxfcs/all/json/APIKEY'

          fetch(url)
            .then(response => {return response.json()})
            .then(data => {
              this.setState(data)
            })      
        }

        render() {
          if(this.state.SiteRep){
              console.log(this.state.SiteRep.DV);
          }

          return <p>TEXT</p>
        }
      }

      export default App

答案 2 :(得分:0)

  

请考虑再经历一次React的组件生命周期here

这就是您的代码中发生的事情:

  1. 您的组件状态被初始化为空对象。
  2. 调用组件的 render() 方法(在这里您不需要数据)。
  3. 生命周期方法componentDidMount()在初始render()之后被调用,您在其中进行API调用并使用响应数据更新状态。

解决此问题的一种方法-

  1. 您可以考虑将状态为isFetching的标志true最初设置为state = { isFetching: true };
render()
  1. 更新您的isFetching方法以显示后备UI,直到您的API调用成功,即... render() { const { isFetching } = this.state; if (isFetching) { return <span> Fetching data </span>; } console.log(this.state.SiteRep.DV) return <p>TEXT</p> } ... 为假;
isFetching
  1. 添加更改以在进行API调用时更新您的... componentDidMount() { // You're going to call the API now, set isFetching to true this.setState({ isFetching: true }); const url = 'http://datapoint.metoffice.gov.uk/public/data/val/wxfcs/all/json/APIKEY' fetch(url) .then(response => {return response.json()}) .then(data => { // API call done, set data and make isFetching false. this.setState({ data, isFetching: false }); }) } ... 标志:

state = {
    SiteRep: {
      DV: {}
    }
}

另一种方法是添加初始状态,例如:

render()
  

使用这种方法,最初您将看不到任何数据,但是在组件状态下更新API响应后,组件将重新呈现。

我个人会采用第一种方法,因为您可以更好地控制自己的let scores = [{name: "A", skills: 500, result: 80}, {name: "B", skills: 6000, result: 90}, {name: "C", skills: 6000, result: 60}, {name: "D", skills: 20, result: 60}, {name: "E", skills: 10, result: 90}]; const maxSkill = scores.reduce((acc, curr) => curr.skills > acc ? curr.skills : acc, 0); const maxResult = scores.reduce((acc, curr) => curr.result > acc ? curr.result : acc, 0); const maxSkillsAndRes = scores.reduce((r, o) => (o.skills === maxSkill || o.result === maxResult) ? [...r,o] : r, []); console.log(maxSkillsAndRes);