ReactJs-我无法在axios循环之外捕获变量

时间:2019-02-10 18:47:55

标签: javascript reactjs

我有一个JSON DB和一个React组件来获取这些数据。 这是我的JSON DB:

{
  "houses": [
    {
      "id": 1,
      "name": "house 1"       
    },
    {
      "id": 2,
      "name": "house 2"        
    },
    {
      "id": 3,
      "name": "house 3"
     }       
  ]
}

它是由ReactJS组件获取的。当我在Axios的循环中执行console.log()时,它可以成功运行。但是在render方法内部,它不起作用。我该如何解决?

class Houses extends Component {
  constructor(props) {
    super(props);
    this.state = {
      index:0,         
      currentHouse:[]      
    };      
  }

  componentDidMount() { 
    axios.get(URL_HOUSES)
      .then(res => {        
        this.setState({ index:0 })
        this.setState({ currentHouse: res.data})          
        //Here is working! It is returning the index and the current house's name      
        console.log('index:' + this.state.index)             
        console.log(
                     'Name of the current house:' +  
                      this.state.currentHouse[this.state.index].name
                    ) 
    }

  render() {                  

    return (
      <div>     
        //Here isn't working. It is returning an error message:  
        //TypeError: Cannot read property '0' of undefined

        <h3>{this.state.currentHouse[this.state.index].name}</h3>
      </div>
    );
  }
}   


export default Houses

2 个答案:

答案 0 :(得分:1)

TL; DR在渲染方法中显示它之前先检查currentHouse初始数组。

在组件的初始呈现中,currentHouse数组中没有元素。

因此,当您的组件尝试打印您的语句this.state.currentHouse[this.state.index].name时,实际上要执行的操作是找到空数组[]的第0个位置。 这将评估为 undefined

解决此问题的选项是在状态下为currentHouse数组设置初始值,或检查数组中是否有值。例如:

 <h3>{this.state.currentHouse.length && this.state.currentHouse[this.state.index].name}</h3>

答案 1 :(得分:0)

此错误的原因是render()方法试图在数据可用之前呈现数据。请尝试以下解决此问题:

class Houses extends Component {
  constructor(props) {
    super(props);
    this.state = {
      index:0,         
      currentHouse:[]      
    };      
  }

  componentDidMount() { 
    axios.get(URL_HOUSES)
      .then(res => {        
        /* Combine into single setState call (this is optional, but 
           makes for cleaner code. Note that calling setState will
           trigger the component to render() again, which will cause
           your currentHouse[0].name to be rendered into <h3> below  */
        this.setState({ index:0, currentHouse: res.data })
    }

  render() {                  

    /* Detect if currentHouse data is ready/avalible - if not, render
       a temporary loading message */
    if(this.state.currentHouse.length === 0) {
       return <p>Loading</p>
    } 

    /* If we reach this point, then there is data in this.state.currentHouse
       that can be accessed and rendered */
    return (
      <div>         
        <h3>{this.state.currentHouse[this.state.index].name}</h3>
      </div>
    );
  }
}   


export default Houses