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.
CodePudding user response:
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 ([{}]
).
CodePudding user response:
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.