简体   繁体   中英

“TypeError: Cannot read property 'name' of undefined” error

The code gives me this "TypeError: Cannot read property 'name' of undefined" error although when I console.log it it gives me the object

import React from "react";

class Random extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      breweries: []
    };
  }

  componentDidMount() {
    fetch("https://api.openbrewerydb.org/breweries")
      .then(response => response.json())
      .then((data) => {
        this.setState({
          breweries: data,
        })
      })
  }

  render() {
    const brewery = this.state.breweries[Math.floor(Math.random()*this.state.breweries.length)];
    return(
      <div>{brewery.name}</div>
    )
  }
}

export default Random;

Until the async request finishes,

this.state.breweries[Math.floor(Math.random()*this.state.breweries.length)] 

will actually return undefined , since

Math.floor(Math.random()*this.state.breweries.length)

will return 0 , and since this.state.breweries is an empty array, it will return undefined

( [][0] -> undefined ).


You have to secure the possibility that brewery is yet undefined, eg:

<div>{brewery && brewery.name}</div>

There are two approaches to this issue.

Approach 1: UNSAFE_componentWillMount()

You could use UNSAFE_componentWillMount() instead of componentDidMount() . UNSAFE_componentWillMount() executes before the component is rendered so you will have the data in the state before the content is rendered. This should get rid of the error.

Approach 2: Verifying the State is !Empty

In your render method, you can add an if statement that says breweries is null if there is no data in state else breweries equals this.state.breweries[Math.floor(Math.random()*this.state.breweries.length)] .

Something like this:

render() {
    const { breweries } = this.state;
    let brewery; 
    if (breweries.length === 0){
       brewery = null;
    } else {
      brewery= 
   this.state.breweries[Math.floor(Math.random()*this.state.breweries.length)];
    }
    return(
      <div>{brewery.name}</div>
    )
  }

For extra insurance, you can combine the two approaches. If you did that your component would look like this:

import React from "react";

class Random extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      breweries: []
    };
  }

  componentWillMount() {
    fetch("https://api.openbrewerydb.org/breweries")
      .then(response =>{ return response.json() })
      .then((data) => {
        this.setState({
          breweries: data,
        })
      })
  }

  render() {
    const { breweries } = this.state;
        let brewery; 
        if (breweries.length === 0){
           brewery = null;
        } else {
          brewery= 
       this.state.breweries[Math.floor(Math.random()*this.state.breweries.length)];
        }
    return(
      <div>{brewery.name}</div>
    )
  }
}

export default Random;

That should do it. Hope this helps.

Edit: WARNING

I wrote willMount() but it should be UNSAFE_componentWillMount(). componentWillMount() will not work after version 17. UNSAFE_componentWillMount() will work after version 17. Sorry about that. I forgot to write unsafe.

You should ensure you've fetched the data, before attempting to access an index of the array. Your random math will evaluate to 0 when the array is empty, resulting in undefined

import React from "react";

class Random extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      breweries: null
    };
  }

  componentDidMount() {
    fetch("https://api.openbrewerydb.org/breweries")
      .then(response => response.json())
      .then((data) => {
        this.setState({
          breweries: data,
        })
      })
  }

  render() {
    if (this.state.breweries) {
      const brewery = this.state.breweries[Math.floor(Math.random()*this.state.breweries.length)];
      return(
        <div>{brewery.name}</div>
      )
    }

    return null
  }
}

export default Random;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM