I am trying to create a nested JSX list items from nested object array. Below is the array:
[
{
"id": 1,
"name": "USA",
"values": [
{
"id": 2,
"name": "Chevy",
"values": [
{
"id": 3,
"name": "Suburban"
},
{
"id": 4,
"name": "Camaro",
"values": [...]
}
]
},
{
"id": 5,
"name": "Ford",
"values": [...]
}
]
}
]
Below is what the array should be converted to:
<ul>
<li>USA
<ul>
<li>Chevy
<ul>
<li>Suburban</li>
<li>Camaro</li>
</ul>
</li>
<li>Ford</li>
</ul>
</li>
</ul>
Here is my approach:
const resultArray = [];
data.forEach((item) => {
resultArray.push(
<li>{item.name}
)
if(item.values){
//recursively iterate and push into array
}
resultArray.push(</li>); //React does not allow this
});
return resultArray;
React does not allow adding individual markups into array. Please help provide a solution.
P.S.: I apologize in advance if you find something wrong with formatting. This is the first time I am posting on stackOverflow.
I am trying to create a nested JSX list items from nested object array. Below is the array:
[
{
"id": 1,
"name": "USA",
"values": [
{
"id": 2,
"name": "Chevy",
"values": [
{
"id": 3,
"name": "Suburban"
},
{
"id": 4,
"name": "Camaro",
"values": [...]
}
]
},
{
"id": 5,
"name": "Ford",
"values": [...]
}
]
}
]
Below is what the array should be converted to:
<ul>
<li>USA
<ul>
<li>Chevy
<ul>
<li>Suburban</li>
<li>Camaro</li>
</ul>
</li>
<li>Ford</li>
</ul>
</li>
</ul>
Here is my approach:
const resultArray = [];
data.forEach((item) => {
resultArray.push(
<li>{item.name}
)
if(item.values){
//recursively iterate and push into array
}
resultArray.push(</li>); //React does not allow this
});
return resultArray;
React does not allow adding individual markups into array. Please help provide a solution.
P.S.: I apologize in advance if you find something wrong with formatting. This is the first time I am posting on stackOverflow.
- Two suggestions: 1) create Different parent & ponents for the differing data-structures. 2) If the nested goes deeper you may want to create something higher order and use recursion. – Jefftopia Commented Dec 14, 2018 at 3:28
4 Answers
Reset to default 12You can "render" your children into a variable and use this directly in your ponent. The trick then is to use a recursive ponent. That way it doesn‘t matter how deep your tree is. You don‘t need to edit this ponent if your tree gets deeper.
Here is how that might look like:
function ListItem({ item }) {
let children = null;
if (item.values) {
children = (
<ul>
{item.values.map(i => <ListItem item={i} key={i.id} />)}
</ul>
);
}
return (
<li>
{item.name}
{children}
</li>
);
}
Here is a working example on Codesandbox with your data.
You should push the entire node to the array at once. Have a render method like this.
const getNode = (data) => {
return (
<ul>
{data.map((item) => (
<li>
USA
<ul>
{item.values && item.values.length
? item.values.map((subItem) => (
<li>
{subItem.name}
<ul>
{subItem.values && subItem.values.length
? subItem.values.map((subSubItem) => <li>{subSubItem.name}</li>)
: null}
</ul>
</li>
))
: null}
</ul>
</li>
))}
</ul>
);
};
And call that method in your render function with the data
const RenderList = (data) => {
return (
<div>
{ getNode(data) }
</div>
);
};
export default Layout;
Here's a full solution example using stencil, which is a framework syntactically similar to React. You can simplify it more by using Array.prototype.reduce
.
import { Component, State } from '@stencil/core';
@Component({
tag: 'app-nested-list-demo'
})
export class NestedList {
@State() foo = [
{
name: 'US',
makers: [
{
name: 'Ford',
models: [
{
name: 'Suburban',
mpg: '9000'
},
{
name: 'Escape',
mpg: '300'
}
]
},
{
name: 'GMC',
models: [
{
name: 'Acadia',
mpg: '11'
},
{
name: 'Envoy',
mpg: 'Yukon'
}
]
}
]
},
{
name: 'Japan',
makers: [
{
name: 'Honda',
models: [
{
name: 'CRV',
mpg: '100'
},
{
name: 'Accord',
mpg: '9000'
}
]
},
{
name: 'Toyota',
models: [
{
name: 'Rav4',
mpg: '10'
},
{
name: 'Camry',
mpg: '400'
}
]
}
]
}
];
render() {
const outerList = this.foo.map(country => {
const middleList = country.makers.map(make => {
const innerList = make.models.map(model => {
return (
<li>{model.name} has {model.mpg} MPG</li>
);
});
return (
<li>
{make.name}
<ul>
{innerList}
</ul>
</li>
);
});
return (
<li>
{country.name}
<ul>
{middleList}
</ul>
</li>
);
});
return (
<ul>
{outerList}
</ul>
);
}
}
I kind of asked the same thing but I already have a script for it, so I'm just looking for a much simpler solution. The script here might help.
// Render a Nested Element based on nested Array