«Не удается прочитать свойство undefined» в React после извлечения и ожидания - PullRequest
0 голосов
/ 07 апреля 2019

Я новичок в React, и у меня проблема с извлечением:

Я выполняю проект по реагированию, в котором мне нужно выбрать пять разных URL-адресов в зависимости от того, какую компанию выбирает пользователь.Я много раз менял код, но он не будет работать.

Я пытался с помощью componentDidMount (но он вызывается только один раз, и я хочу получить много URL-адресов), используя «while (! This.состояние) "занято, ждать извлечения, чтобы получить данные, прежде чем присвоить их и т. д.

Функция выборки:

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 голосов
/ 07 апреля 2019

Причина этой проблемы в том, что setState() является асинхронным . В вашем случае это означает, что изменения состояния, сделанные здесь:

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, open и higher были доступны и отображались непосредственно в render(), а не кэшировать эти значения где-либо еще как Вы, кажется, делаете. Так что попробуйте что-то вроде этого:

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>
      );
    }
  }
0 голосов
/ 08 апреля 2019

Я нашел решение:

Просто вставьте оператор if перед возвратом в render, говоря: "Изменился ли символ? Если да, извлекайте, иначе нет"

0 голосов
/ 07 апреля 2019

Я думаю, что это потому, что вы вызываете this.fetch_data ();внутри render () это означает, что сначала у вас нет данных в вашем состоянии, а после того, как есть данные, вы обновляете свой компонент, поэтому вы снова и снова вызываете this.fetch_data ();

, ищите Reactжизненный цикл компонента: https://code.likeagirl.io/understanding-react-component-life-cycle-49bf4b8674de

еще одну вещь не нужно писать while (), потому что вы используете async await.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...