Let's say I have got an object like this which I'm using to create a material navbar in React:
const menu = {
DASHBOARD: [
{
name: ViewPage1
type: VIEW
},
{
name: ViewPage2
type: VIEW
},
{
name: RunPage1
type: RUN
},
{
name: RunPage2
type: RUN
},
],
}
My goal is to render the "type" label (View or Run) just once. So have something like this:
----VIEW
ViewPage1
ViewPage2
----RUN
RunPage1
RunPage2
I tried like this:
{Object.keys(menu).map((key) => (
<>
<Button>
{key}
</Button>
<Menu>
<div>
{menu[key].map((menuItem) => (
<TypeLabelComponent label={menuItem.type} size="small" variant="outlined" />
<MenuItem>
{menuItem.name}
</MenuItem>
))}
</div>
</Menu>
</>
))}
But obviously, it renders the TYPE label every time he loops in the map. So my result is the following:
----VIEW
ViewPage1
----VIEW
ViewPage2
----RUN
RunPage1
----RUN
RunPage2
How can I handle this to render the TYPE label only if it is not already being rendered?
First aggregate the dashboard into object keys as type and values are array of names.
const menu = {
DASHBOARD: [
{
name: "ViewPage1",
type: "VIEW",
},
{
name: "ViewPage2",
type: "VIEW",
},
{
name: "RunPage1",
type: "RUN",
},
{
name: "RunPage2",
type: "RUN",
},
],
};
const Component = () => {
const data = menu.DASHBOARD.reduce((acc, curr) => {
if (!acc[curr.type]) {
acc[curr.type] = [];
}
acc[curr.type].push(curr.name);
return acc;
}, {});
return (
<div>
{Object.entries(data).map(([type, names]) => {
return (
<div key={type}>
<div>{`--------${type}`}</div>
{names.map((name) => (
<div key={name}>{name}</div>
))}
</div>
);
})}
</div>
);
};
ReactDOM.render(<Component />, document.getElementById("app"));
<script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
<div id="app"></div>