读取并等待后,React中的“无法读取未定义的属性”

时间:2019-04-07 19:56:03

标签: javascript json reactjs fetch

我是React的新手,提取时遇到问题:

我一直在做一个反应项目,根据用户选择的公司,我必须从五个不同的URL中获取。 我已经多次更改了代码,但无法正常工作。

我尝试使用componentDidMount(但是它只被调用一次,并且我想获取许多url),并使用“ while(!this.state)”忙于等待获取以获取数据,然后再分配它,等等。 / p>

获取功能:

async fetch_data() {
    var sel = this.props.select;
    symbol = companies[sel];
    url = 'https://www.alphavantage.co/query?function=' + func + '&symbol=' + symbol + '&outputsize=' + osize + '&apikey=' + api_key;
    var response = await fetch(url);
    var data = await response.json();

    while(!data);

    this.setState({data: data, loading: false });
    this.setValues();    
  }

设置值功能(已修剪,因此不会太长):

setValues() {
    day = this.state.data["Meta Data"]["3. Last Refreshed"];
    open = this.state.data["Time Series (Daily)"][day]["1. open"];
    higher = this.state.data["Time Series (Daily)"][day]["2. high"];
  }

渲染功能(也已修剪):

render() {

    this.fetch_data();
    if(this.state.loading || !this.state || !this.state.data) {
      return <div>Loading :D...</div>
    } else {
      return (
        <div>
          <h2>Symbol: {symbol}</h2>
          <p>Url: {url}</p>
          <ul>
            <li>
              Open price: {open}
            </li>
            <li>
              Higher price: {higher}
            </li>
          </ul>
        </div>
      );
    }
  }

当用户选择公司时,我实际上已经完成了工作,并且符号(和URL)发生了变化... 但是问题是,例如,当程序要访问this.state.data["Time Series (Daily)"][day]["1. open"];时,它会由于获取和接收数据而崩溃。

错误提示:

Unhandled Rejection (TypeError): Cannot read property '3. Last Refreshed' of undefined:

  42 | setValues() {
> 43 |   day = this.state.data["Meta Data"]["3. Last Refreshed"];
     | ^  44 |   open = this.state.data["Time Series (Daily)"][day]["1. open"];
  45 |   higher = this.state.data["Time Series (Daily)"][day]["2. high"];

应用程序并不总是崩溃,它会显示结果,但是渲染组件会继续调用this.fetch_data(),并且它崩溃是因为有时(如80%的时间)数据没有到达,我我正在尝试访问它。

3 个答案:

答案 0 :(得分:0)

我认为这是因为您正在调用this.fetch_data();内部render() 这意味着首先您没有状态的数据,而在有数据之后您正在更新组件,因此您一次又一次地调用this.fetch_data();

看一下React组件的生命周期:https://code.likeagirl.io/understanding-react-component-life-cycle-49bf4b8674de

另一件事无需编写while(),因为您正在使用异步等待。

答案 1 :(得分:0)

此问题的原因是setState() is asynchronous。在您的情况下,这意味着状态在这里进行了更改:

this.setState({data: data, loading: false });

在随后对this.setValues();的调用(它本身依赖于在组件状态下定义的data对象)上不是立即可观察到的。 这些情况的解决方案是在setState()方法上使用第二个回调参数来运行依赖于相应状态更改的逻辑:

/* The state change will be observable when setValues() is called via
the callback */
this.setState({data: data, loading: false }, () => {

    this.setValues();    
});

作为组件实现的建议,请考虑修改render()方法,以便在day中访问openhigherrender()并进行渲染。直接,而不是像看起来那样将这些值缓存到其他位置。所以尝试这样的事情:

render() {

    this.fetch_data();
    if(this.state.loading || !this.state || !this.state.data) {
      return <div>Loading :D...</div>
    } else {

      /* Call to setValues() no longer needed */

      const day = this.state.data["Meta Data"]["3. Last Refreshed"];
      const open = this.state.data["Time Series (Daily)"][day]["1. open"];
      const higher = this.state.data["Time Series (Daily)"][day]["2. high"];

      return (
        <div>
          <h2>Symbol: {symbol}</h2>
          <p>Url: {url}</p>
          <ul>
            <li>
              Open price: {open}
            </li>
            <li>
              Higher price: {higher}
            </li>
          </ul>
        </div>
      );
    }
  }

答案 2 :(得分:0)

我找到了解决方法:

只需在返回之前将if语句放在render中,然后说“符号是否已更改?如果是,则获取,否则不”。