0

I'm working on a react project, and currently trying to access some data within the following nested object:

{name: "Products", attributes: {…}, children: Array(1), value: "", getElementsByTagName: ƒ}

This object is being passed as the prop 'beerList', so in my component, props.beerList.children logs the following to the browser:

[
{name: "Beers", attributes: {…}, children: Array(17), value: "", getElementsByTagName: ƒ}
]

So here's where I'm having trouble. I want to access the array of 17 objects corresponding to the 'children' key in the object above. I tried console.logging props.beerList.children[0], however I got the following error:

Uncaught TypeError: Cannot read property '0' of undefined

I'm not sure why this isn't working - it should return the object containing the array, since the object is at the 0 index of the array. Anyway, here's a more detailed look at the object I'm working with. It's not the complete object, but I'm including it to give an idea of what the overall data structure looks like:

{
  name: 'Products', attributes:{}, value:'', children: [
    {
      name:'Beers', attributes: {}, value: '', children: [
        {
          name: 'Product', attributes:{}, value:'', children: {
            
          }
        }
      ]
    }
  ]
}

Home.js parent component:

class Home extends React.Component {
    constructor() {
        super()
        this.state = {
            beers:[],
            test: 'test'
        }
    }

    componentDidMount() {
        const url = 'http://www.hashigozake.co.nz/taplist.xml'
        const proxyURL = 'https://cors-anywhere.herokuapp.com/'
      
        fetch(proxyURL + url)
        .then(res => res.text())
        .then(beerXML => {
          let beerJs = new XMLParser().parseFromString(beerXML)
          this.setState({
            beers: beerJs
          })
        })
      }

    render() {
    
    return (
        <div className = 'home'>
            <nav className = 'nav'>
                <ul>
                    <Link to = '/about' style={{ textDecoration: 'none' }} >
                        <li className='list'>About</li>
                    </Link>
                    <li className='list'>Food</li>
                    <li className='list'>Events</li>
                    <li className='list'>News</li>
                    <Link to ='/shop' style={{ textDecoration: 'none' }} >
                        <li className='list'>Shop</li>
                    </Link>
                    <li className='list'>Contact</li>
                    <li className='list'>Blog</li>
                </ul>
            </nav>
            <main>
                <div className='main__image'>
                    <img src= {hashi_logo_2}/>
                </div>
                <div>
                    <TileList beerList = {this.state.beers}/>

'TileList' component where fetched data is being mapped over

import React from 'react'
import Tile from './Tile'

const TileList = (props) => {
    console.log(props.beerList.children)
    return (
        <>
         <h1 className = 'h1-pouring'>Currently Pouring:</h1> 
        <div className = 'tile-container'>
            {
                props.beerList.map(item => {
                    return <Tile 
                    />
                })
            } 
        </div> 
        </>
    )
}

export default TileList

Thanks

6
  • 1
    It would help to see some actual code that performs this. Because the error indicates that the beersList exists, however it doesn't have children key defined at all - hence no array. So it might be an issue with the data. Commented Jul 27, 2020 at 0:27
  • just added some more code Commented Jul 27, 2020 at 0:31
  • Try props.beerList[0].children instead Commented Jul 27, 2020 at 0:36
  • thanks for the suggestion @Knick - I tried it out but it gave me the following error: Uncaught TypeError: Cannot read property 'children' of undefined Commented Jul 27, 2020 at 0:39
  • 1
    The render function of your home.js runs way before your fetch would return with data. As you don't have any kind of condition on when TileList is rendered, it attempts to build it with the state.beers before the children have been populated. You need to either add a condition in the render or map TileList to a variable. Then output the variable in the render function which will only output null before it is set to the TileList component on fetch response. Commented Jul 27, 2020 at 0:52

1 Answer 1

1

You are trying to access beersList when it still doesn't exist. The data is being fetched, so it's an async code. You have to make sure that the data is available when you're trying to access it.

This should fix the error:

{
    this.state.beers && this.state.beers.length > 0 ? (
        <TileList beerList = {this.state.beers}/>
    ) : (
        <span>Fetching data...</span>
    )
}

just replace your <TileList> element call in Home.js with this snippet.

However the solution is crude and would need some more sophisticated loader mechanism. The given hack doesn't cover a case when data is done fetching, but it returned no results.

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks Wiktor! I see what the problem is now. I tried your code snippet, but the browser hung on 'Fetching data'. I think the conditional statement could be looking at the wrong property - since this.state.beers returns an object, not an array, the .length method won't work.
I'm glad that my answer at least helped you move the issue in the right direction. Good luck!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.