无法读取未定义的属性“ map”,但实际上可以在控制台中看到数据

时间:2018-11-28 18:10:02

标签: reactjs redux

基本上,我有一个组件可以调用与IMDB相关的API并将结果发送回去,我可以在控制台中看到结果,但是由于某些原因我无法映射它!

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));

screenshot to the console

My Reducer

My Action

3 个答案:

答案 0 :(得分:0)

您的问题很可能是您调用地图时结果为空,但是当您登录到控制台时,已经填充的值。您应该检查值是否被异步填充,如果是,则仅在值被填充时才调用地图。

答案 1 :(得分:0)

请记住,render将在componentDidMount之前被调用,因此您的Redux存储在第一次渲染时将为空。在您的fetchMovieResults中,您的默认行为是遍历this.props.assets.SearchResult.Search,直到异步调用结束为止,该undefined将会是this.props.assets.fetchResultsErrorthis.props.assets.loadingResultsundefined都将是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 } 上进行检查:

const arr = [
  { name: 'Bob', age: 12 },
  { name: 'Sam', age: 21 },
  { name: 'Karen', age: 45 }
];

// Without
console.log(JSON.stringify(arr));
 
// With
console.log(JSON.stringify(arr, null, 2));

答案 2 :(得分:0)

我编写的获取方法具有多种可能的状态,可以在没有错误的每种情况下使用。

此操作的基本思路:您检查所有可能的状态,但如果不匹配,则返回加载状态。

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 代码在首次渲染组件后触发(这是一种好习惯)。

这意味着您的动作已触发,reduce的第一个渲染器添加了loadingResults状态 AFTER ,这表示:

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
}

我的回答在每种情况下都有效,因为默认情况下是“加载”状态。