Не могу прочитать свойство 'map' из undefined, но я действительно могу увидеть данные в консоли - PullRequest
0 голосов
/ 28 ноября 2018

В основном, у меня есть этот компонент, который вызывает API-интерфейс, связанный с IMDB, и отправляет результат обратно. Я вижу результат в консоли, но по какой-то причине НЕ МОГУ отображать его!

import React, { Component } from 'react'
import { connect } from 'react-redux'
import { withRouter } from 'react-router-dom'
import { searchMovieIMDB } from '../../../actions'

class MovieFormReview extends Component {
    componentDidMount() {
        this.props.searchMovieIMDB(this.props.formValues.title);
    }
    fetchMovieResults() {
        if(this.props.assets.fetchResultsError) {
            return (
                <div className="loading">
                    <h1>{this.props.assets.fetchResultsError}</h1>
                </div>
            );
        } else if(this.props.assets.loadingResults) {
            return (
                <div className="loading">
                    <h1>Loading...</h1>
                </div>
            );
        } else {
            return this.props.assets.SearchResult.Search.map(series => (
                    <div className="latest" key={series._id}>
                        <h1>{series.title}</h1>
                    </div>
                )
            )
        }
    }
    render() {
        console.log(this.props.assets.SearchResult.Search);
        return (
            <div className="add-new-asset">
                <h2>Please confirm your movie.</h2>
                {this.fetchMovieResults()}
            </div>
        )
    }
}

const mapStateToProps = ({ form, assets }) => {
    return {
        formValues: form.movieForm.values,
        assets
    }
}

export default connect(mapStateToProps, { searchMovieIMDB })(withRouter(MovieFormReview));

снимок экрана для консоли

Мой редуктор

Мое действие

Ответы [ 3 ]

0 голосов
/ 28 ноября 2018

Имейте в виду, что render будет вызываться раньше componentDidMount, поэтому ваш магазин Redux будет пуст при первом рендере.В вашем fetchMovieResults вашим поведением по умолчанию является итерация по this.props.assets.SearchResult.Search, которая будет undefined до завершения асинхронного вызова.И this.props.assets.fetchResultsError, и this.props.assets.loadingResults также будут undefined, заканчиваясь на else, который вызывает ошибку.

Простое решение, проверьте это на else:

fetchMovieResults() {
    if(this.props.assets.fetchResultsError) {
        return (
            <div className="loading">
                <h1>{this.props.assets.fetchResultsError}</h1>
            </div>
        );
    } else if(this.props.assets.loadingResults) {
        return (
            <div className="loading">
                <h1>Loading...</h1>
            </div>
        );
    } else if( typeof this.props.assets.Search !== 'undefined' &&
               typeof this.props.assets.SearchResult.Search !== 'undefined') {
        return this.props.assets.SearchResult.Search.map(series => (
                <div className="latest" key={series._id}>
                    <h1>{series.title}</h1>
                </div>
            )
        )
    }

    return null
}
0 голосов
/ 28 ноября 2018

Я пишу методы выборки с несколькими возможными состояниями, как это, работает в любой ситуации без ошибок.

Общая идея, стоящая за этим: вы проверяете все возможные состояния, но если ни одно не совпадает, возвращаете состояние загрузки.

fetchMovieResults() {
  const {assets} = this.props;      

  if (assets) {
    if (assets.fetchResultsError) {
      // if error
      return (
        <div className="loading">
          <h1>{assets.fetchResultsError}</h1>
        </div>
      );
    } else if (assets.SearchResult && assets.SearchResult.Search && assets.SearchResult.Search.length > 0) {
      // if data and more than 0
      return assets.SearchResult.Search.map(series => (
        <div className="latest" key={series._id}>
          <h1>{series.title}</h1>
        </div>
      ));
    }
  }

  // no error or data
  // has to be loading
  return (
    <div className="loading">
       <h1>Loading...</h1>
    </div>
  );
}

Редактировать

Почему мой код работает, а ваш - нет?

(Это предположение, потому что я не знаю весь ваш код)

componentDidMount запускается после того, как компонент монтируется и отображается в первый раз, что означает, что ваш код fetch API запускается после того, как компонент уже отображается в первый раз (что является хорошей практикой).

Это означает, что ваше действие выполняется, и редуктор добавляет loadingResults состояние ПОСЛЕ первого рендера, что означает:

if (this.props.assets.fetchResultsError) {
  // this check fails
} else if (this.props.assets.loadingResults) {
  // this check fails
} else {
  // this code runs but you don't have
  // data yet and you'll get an error
}

Мой ответ работает в любой ситуации, потому чтосостояние "загрузка" является параметром по умолчанию.

0 голосов
/ 28 ноября 2018

Скорее всего, ваша проблема в том, что при вызове карты результат будет нулевым, но при входе в консоль значения уже заполнены.вы должны проверить, заполнено ли значение асинхронно, и если это так, вы должны вызывать карту только после заполнения значений.

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