尝试使用React检索API数据时出现问题

时间:2019-11-18 20:20:11

标签: javascript reactjs api

由于某种原因,我无法访问结果数组中的“问题”键。有人可以帮忙吗?这只是我已经开始的一个辅助项目,并且已经花了好几个小时试图将这第一部分基本内容付诸实践。我至今仅使用React和API已有大约一周的时间,而且我经验不足,所以可以提供任何帮助。

import React from 'react'
import ReactDOM from 'react-dom'

class App extends React.Component {

  constructor() {
    super()
    this.state = {
      questionList: []

    }
  }

  componentDidMount() {
    fetch('https://opentdb.com/api.php?amount=10')
      .then(resp => resp.json())
      .then(resp => this.setState({ questionList: resp }))
  }

  render() {
    return (
      <div>{this.state.questionList.results[0].question}</div>

    )
  }
}


ReactDOM.render(
  <App />,
  document.getElementById('root')
)

这是API数据-

{
  "response_code": 0,
  "results": [
    {
      "category": "Entertainment: Film",
      "type": "multiple",
      "difficulty": "medium",
      "question": "Which of the following James Bond villains is not affiliated with the SPECTRE organization?",
      "correct_answer": "Auric Goldfinger",
      "incorrect_answers": [
        "Dr. Julius No",
        "Rosa Klebb",
        "Emilio Largo"
      ]
    },
    {
      "category": "Geography",
      "type": "multiple",
      "difficulty": "hard",
      "question": "The mountainous Khyber Pass connects which of the two following countries?",
      "correct_answer": "Afghanistan and Pakistan",
      "incorrect_answers": [
        "India and Nepal",
        "Pakistan and India",
        "Tajikistan and Kyrgyzstan"
      ]
    },
    {
      "category": "Entertainment: Video Games",
      "type": "multiple",
      "difficulty": "medium",
      "question": "In Team Fortress 2, which class wields a shotgun?",
      "correct_answer": "Everyone Listed",
      "incorrect_answers": [
        "Heavy",
        "Soldier",
        "Engineer"
      ]
    },
    {
      "category": "Entertainment: Video Games",
      "type": "multiple",
      "difficulty": "easy",
      "question": "Who is the leader of Team Mystic in Pok&eacute;mon Go?",
      "correct_answer": "Blanche",
      "incorrect_answers": [
        "Candela",
        "Spark",
        "Willow"
      ]
    },
    {
      "category": "Science & Nature",
      "type": "multiple",
      "difficulty": "easy",
      "question": "The medical term for the belly button is which of the following?",
      "correct_answer": "Umbilicus",
      "incorrect_answers": [
        "Nevus",
        "Nares",
        "Paxillus"
      ]
    },
    {
      "category": "Entertainment: Cartoon & Animations",
      "type": "multiple",
      "difficulty": "easy",
      "question": "What is lost in Hawaiian and is also the name of a little girl in a 2002 film which features a alien named &quot;Stitch&quot;?",
      "correct_answer": "Lilo",
      "incorrect_answers": [
        "Lolo",
        "Lucy",
        "Lulu"
      ]
    },
    {
      "category": "Entertainment: Cartoon & Animations",
      "type": "multiple",
      "difficulty": "hard",
      "question": "In &quot;Gravity Falls&quot;, what does Quentin Trembley do when he is driven out from the White House?",
      "correct_answer": "Eat a salamander and jump out the window.",
      "incorrect_answers": [
        "Leave in peace.",
        "Jump out the window.",
        "Release 1,000 captive salamanders into the white house."
      ]
    },
    {
      "category": "Entertainment: Television",
      "type": "multiple",
      "difficulty": "hard",
      "question": "Who was the winner of &quot;Big Brother&quot; Season 10?",
      "correct_answer": "Dan Gheesling",
      "incorrect_answers": [
        "Bryce Kranyik",
        "Ryan Sutfin",
        "Chris Mundorf"
      ]
    },
    {
      "category": "General Knowledge",
      "type": "multiple",
      "difficulty": "easy",
      "question": "Terry Gilliam was an animator that worked with which British comedy group?",
      "correct_answer": "Monty Python",
      "incorrect_answers": [
        "The Goodies&lrm;",
        "The League of Gentlemen&lrm;",
        "The Penny Dreadfuls"
      ]
    },
    {
      "category": "Entertainment: Video Games",
      "type": "multiple",
      "difficulty": "easy",
      "question": "In Counter-Strike: Global Offensive, what&#039;s the rarity of discontinued skins called?",
      "correct_answer": "Contraband",
      "incorrect_answers": [
        "Discontinued",
        "Diminshed",
        "Limited"
      ]
    }
  ]
}

谢谢!

4 个答案:

答案 0 :(得分:1)

这肯定会失败,因为您正在调用异步操作,但是您的渲染显式依赖于此:

{this.state.questionList.results[0].question}

  

您可能会收到Cannot read property 'question' of undefined

  

无法读取property '0' of undefined

最基本的解决方案是检查questionList内是否确实有一些数据。

注意:数组中的questionList,而不是对象。

render() {
   if (this.state.questionList.length === 0) {
      return null;
   }

   return (
     <div>{this.state.questionList[0].results[0].question}</div>
   );
 }

尽管最好,但最长的解决方案是逐步检查questionList具有正确的结构:

{this.state.questionList[0] 
    && this.state.questionList.results
    && this.state.questionList.results[0] 
    && this.state.questionList.results[0].question}

答案 1 :(得分:1)

正如其他人所指出的,您的API调用将花费一段时间,并且App将在完成之前呈现,因此在呈现时您的数据还不存在。您基本上是在尝试获取尚不存在的数据。

我喜欢在状态上显示一个loading标志来显示正在加载的东西,以及一个error标志来标识任何传入的错误。

import React from 'react'
import ReactDOM from 'react-dom'

class App extends React.Component {

  constructor() {
    super()
    this.state = {
      questionList: {
        isLoading: true,
        error: null,
        data: null,
      }

    }
  }

  componentDidMount() {
    fetch('https://opentdb.com/api.php?amount=10')
      .then(resp => resp.json())
      .then(resp => this.setState(
        {questionList: 
         {data: resp, isLoading: false, error: null} 
       }))
      .catch(e => this.setState({questionList: {data: null, error: e, data: null}}))
  }

  render() {
    if (this.state.questionList.isLoading)
      return <Loading />
    if (this.state.questionList.error)
     return <Error error={this.state.questionList.error} />
    return (
      <div>{this.state.questionList.data.results[0].question}</div>

    )
  }
}


ReactDOM.render(
  <App />,
  document.getElementById('root')
)

您可以而且应该在检查,数据修复等方面更加聪明……但这就是我如何处理它的要旨。

我还建议将您的API调用包装在模块中。因此,您可以说api.questions.getList().then(...)而不是在组件中进行提取,而是可以将任何数据转换或其他难看的东西放入这些模块中。它与您的问题并没有真正的联系(反正这可能会过大了),但是由于您似乎是新手,所以我会为您解决。

答案 2 :(得分:0)

使用 console.log in render()

,您将看到状态为空,因为您调用了异步函数。

有:

  1. Api通话-可能需要1秒,10秒,20秒等...
  2. 调用render()-您的状态为空,因为您需要等待API响应
  3. 您会收到错误消息...

您可以添加一些代码,例如:

  render() {
    if (this.state.questionList.length === 0) {
        return '<div>Loading...</div>';
    }

    return (
      <div>{this.state.questionList.results[0].question}</div>

    )
  }

答案 3 :(得分:-2)

我不确定您的结果在呈现时是否会返回到该组件。我认为您需要运行检查以查看结果是否在那里。你可以尝试这样的事情,我们可以从这里去吗?

{this.state.questionList.results.length > 1 && this.state.questionList.results[0].question}