0

I have data as Array of Array in my content.js component which should serve my parent component Catalogues.js to display the data passed as props to child component Groups.js. content.js file is:

const content = [
  [
    {
      id: 1,
      category: 'Hymns',
      track1:
      [
        {
          title: 'Song 1',
          text: 'When peace like a river attendeth my way',
        },
      ],
      track2:
      [
        {
          title: 'Song 2',
          text: 'It is well with my soul',
        },
      ],
      track3:
      [
        {
          title: 'Song 3',
          text: 'Praise the Lord, praise the Lord',
        },
      ],
    },
  ],
  [
    {
      id: 2,
      category: 'Rock',
      track1:
      [
        {
          title: 'Song 1',
          text: 'Open the eyes of my heart',
        },
      ],
      track2:
      [
        {
          title: 'Song 2',
          text: 'Here is our god',
        },
      ],
      track3:
      [
        {
          title: 'Song 3',
          text: 'Becaue he lives',
        },
      ],
    },
  ],
  [
    {
      id: 3,
      category: 'High Life',
      track1:
      [
        {
          title: 'Song 1',
          text: 'I will bless thye lord at all times',
        },
      ],
      track2:
      [
        {
          title: 'Song 2',
          text: 'Who is like unto thee',
        },
      ],
      track3:
      [
        {
          title: 'Song 3',
          text: 'Blesed be the name of the Lord',
        },
      ],
    },
  ],
];
export default content;

The child Group.js component is:

import React from 'react';
import { FaLevelDownAlt } from 'react-icons/fa';
import './groups.css';

const Groups = ({ item: { category, track1, track2, track3 } }) => (
  <div className="groups-container">
    <div className="category">
      <p className="categoryArrows">
        <FaLevelDownAlt color="#2b74b7" size={35} />
      </p>
      <p className="categoryTitle">{category}</p>
    </div>
    <div className="alltracks">
      <div className="track">
        <h1>{track1.title}</h1>
        <p>{track1.text}</p>
      </div>
      <div className="tracks">
        <h1>{track2.title}</h1>
        <p>{track2.text}</p>
      </div>
      <div className="track">
        <h1>{track3.title}</h1>
        <p>{track3.text}</p>
      </div>
    </div>
  </div>

);

export default Groups;

And the parent component Catalogues.js is:

import React, { useEffect } from 'react';
import Groups from '../../components/Groups';
import content from './content';

const Catalogues = () => (
  <div className="catalogues-section">
    <div className="catalogues-heading">
      <h1 className="catalogues-text">Songs in the service</h1>
    </div>
    <div className="catalogues-container">
      {content.map((item, index) => (
        <Groups key={index} item={item} />
      ))}
    </div>
  </div>
);

export default Catalogues;

The problem is that the browser keeps showing “Cannot read property 'category' of undefined”. I have tried many possibilities found on internet but not to avail. Sometimes it says “Cannot read property 'title' of undefined”, but I’m used with passing props in React. I fail to understand what is going on in this case. Can somebody tell me how to solve this issue? I’ll really appreciate.

1
  • Your content seems to be badly formatted. Pay attention to the [] around each object. Commented Dec 29, 2021 at 20:21

3 Answers 3

2

Your content is probably not in the format that you want it to be -- you're using a bunch of unnecessary [] which are creating extra arrays where you don't need them. If you change your content to the following, your code should work:

const content = [
  
    {
      id: 1,
      category: 'Hymns',
      track1:
        {
          title: 'Song 1',
          text: 'When peace like a river attendeth my way',
        },
      track2:
        {
          title: 'Song 2',
          text: 'It is well with my soul',
        },
      track3:
        {
          title: 'Song 3',
          text: 'Praise the Lord, praise the Lord',
        },
    },
  
    {
      id: 2,
      category: 'Rock',
      track1:
        {
          title: 'Song 1',
          text: 'Open the eyes of my heart',
        },
      track2:
        {
          title: 'Song 2',
          text: 'Here is our god',
        },
      track3:
        {
          title: 'Song 3',
          text: 'Becaue he lives',
        },
    },
  
    {
      id: 3,
      category: 'High Life',
      track1:
        {
          title: 'Song 1',
          text: 'I will bless thye lord at all times',
        },
      track2:
      
        {
          title: 'Song 2',
          text: 'Who is like unto thee',
        },
      
      track3:
      
        {
          title: 'Song 3',
          text: 'Blesed be the name of the Lord',
        },
      
    },
];

Note how now, for example, each track1 is just an object ({}) and not an array of objects ([{}]).

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

2 Comments

But this is what I had in the beginning, and It says "Cannot read property 'category' of undefined". That's why I started changing it to arrays of array. Thanks for confirming it. what to do then
Couldn't vote up, now I do
1

I reproduced your codes and got the items displayed properly. Every time you face "undefined" you need to console log the content and see whether or not it is found by parent component. Your content format is not relevant for the map() function to map through it since it will map through array of object, just like @jnpdx mentioned earlier. So take advantage on his format and do document.write(content) to see whether you get [object object]. If you get that then you can continue with this answer. Otherwise your import of 'content' may be also wrong. this is the right content format:

const content = [
  
    {
      id: 1,
      category: 'Hymns',
      track1:
        {
          title: 'Song 1',
          text: 'When peace like a river attendeth my way',
        },
      track2:
        {
          title: 'Song 2',
          text: 'It is well with my soul',
        },
      track3:
        {
          title: 'Song 3',
          text: 'Praise the Lord, praise the Lord',
        },
    },
  
    {
      id: 2,
      category: 'Rock',
      track1:
        {
          title: 'Song 1',
          text: 'Open the eyes of my heart',
        },
      track2:
        {
          title: 'Song 2',
          text: 'Here is our god',
        },
      track3:
        {
          title: 'Song 3',
          text: 'Because he lives',
        },
    },
  
    {
      id: 3,
      category: 'High Life',
      track1:
        {
          title: 'Song 1',
          text: 'I will bless the lord at all times',
        },
      track2:
      
        {
          title: 'Song 2',
          text: 'Who is like unto thee',
        },
      
      track3:
      
        {
          title: 'Song 3',
          text: 'Blessed be the name of the Lord',
        },
      
    },
];

Then assuming that you get [object object] by document.write(content), in the Catalogues.js change yours by this:

import React, { useEffect } from 'react';
import Groups from '../../components/Groups';
import content from './content';

const Catalogues = () => (
  <div className="catalogues-section">
    <div className="catalogues-heading">
      <h1 className="catalogues-text">Songs in the service</h1>
    </div>
    <div className="catalogues-container">
      {content.map((item, index) => (
        <Groups key={index} category={item.category} title1={item.track1.title} text1={item.track1.text} title2={item.track2.title} text2={item.track2.text} title3={item.track3.title} text3={item.track3.text}/>
      ))}
    </div>
  </div>
);

export default Catalogues;

Because you have nested objects inside your objects.

Then change your Groups.js by:
import React from 'react';
import { FaLevelDownAlt } from 'react-icons/fa';
import './groups.css';

const Groups = ({ category, title1, text1, title2, text2, title3, text3 }) => (
  <div className="groups-container">
    <div className="category">
      <p className="categoryArrows">
        <FaLevelDownAlt color="#2b74b7" size={35} />
      </p>
      <p className="categoryTitle">{category}</p>
    </div>
    <div className="alltracks">
      <div className="track">
        <h1>{title1}</h1>
        <p>{text1}</p>
      </div>
      <div className="tracks">
        <h1>{title2}</h1>
        <p>{text2}</p>
      </div>
      <div className="track">
        <h1>{title3}</h1>
        <p>{text3}</p>
      </div>
    </div>
  </div>

); 

It's more about iteration sake. Because doing what you did like <Groups key={index} item={item} /> and const Groups = ({ item: { category, track1, track2, track3 } }) => (...) I gets the 'category' props, but it didn't map through the tracks nested object to pick 'title' and 'text' for each.

2 Comments

It works. But why wouldn't Groups = ({ item: { category, track1, track2, track3 } }) => (...) give same result?
You were having that problem because track1, track2, track3 are objects inside object, and the Groups.js component could not get their properties. That's why category value was fetched but not the tracks properties.
0

first you need convert string to array just do JSON.parse( your props)

1 Comment

As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.

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.