You're not returning the result in this map `{navItem.content.map(item => {this.getNavItem(item)})}`. Should be `{navItem.content.map(item => this.getNavItem(item))}` or `{navItem.content.map(item => { return this.getNavItem(item)})}`. See below example (I replaced your components with divs but the structure is right):
<!-- begin snippet: js hide: false console: true babel: true -->
<!-- language: lang-js -->
const navContent = [
{
type: "link",
target: "/",
content: "Home"
},
{
type: "dropdown",
title: "CLICK ME",
content: [
{ type: "item", target: "/", content: "home" },
{ type: "item", target: "/", content: "home" }
]
},
{
type: "form",
formType: "text",
placeholder: "search",
className: "",
buttonType: "submit",
buttonContent: "Submit"
}
];
class Navigation extends React.Component {
constructor(props) {
super(props);
this.state = {};
}
getNavItem(navItem) {
const foo = () => 1;
switch (navItem.type) {
case "link":
return (
<div className="Nav.Link">
<div className="Link" to={navItem.target}>
{navItem.content}
</div>
</div>
);
case "dropdown":
return (
<div
className="NavDropdown"
id="basic-nav-dropdown"
title={navItem.title}
>
{navItem.content.map((item) => this.getNavItem(item))}
</div>
);
case "form":
return (
<div className="Form" inline>
{" "}
<div
className="FormControl"
type={navItem.formType}
placeholder={navItem.placeholder}
className={navItem.className}
/>
<div className="Button" type={navItem.buttonType}>
{navItem.buttonContent}
</div>
</div>
);
case "item":
return (
<div className="NavDropdown.Item">
<div className="Link" to={navItem.target}>
{navItem.content}
</div>
</div>
);
}
}
render() {
return (
<div className="Navbar" bg="light" expand="lg">
<div className="Link" to="/">
<div className="Navbar.Brand">Home Placeholder</div>
</div>
<div className="Navbar.Toggle" aria-controls="basic-navbar-nav" />
<div className="Navbar.Collapse" id="basic-navbar-nav">
<div className="Navbar.Collapse mr-auto">
{this.props.navContent.map(this.getNavItem.bind(this))}
</div>
</div>
</div>
);
}
}
ReactDOM.render(
<Navigation navContent={navContent} />,
document.getElementById("react")
);
<!-- language: lang-html -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<Navigation/>
<div id="react"></div>
<!-- end snippet -->
That's *property spread notation*. It was added in ES2018, but long-supported in React projects via transpilation (as "JSX spread attributes" even though you could do it elsewhere, too, not just attributes).
`{...this.props}` *spreads out* the "own" properties in `props` as discrete properties on the `Modal` element you're creating. For instance, if `this.props` contained `a: 1` and `b: 2`, then
<Modal {...this.props} title='Modal heading' animation={false}>
would be the same as
<Modal a={this.props.a} b={this.props.b} title='Modal heading' animation={false}>
But it's dynamic, so whatever "own" properties are in `props` are included.
Since `children` is an "own" property in `props`, spread will include it. So if the component where this appears had child elements, they'll be passed on to `Modal`. Putting child elements between the opening tag and closing tags is just syntactic sugar — the good kind — for putting a `children` property in the opening tag. Example:
<!-- begin snippet: js hide: true console: true babel: true -->
<!-- language: lang-js -->
class Example extends React.Component {
render() {
const { className, children } = this.props;
return (
<div className={className}>
{children}
</div>
);
}
}
ReactDOM.render(
[
<Example className="first">
<span>Child in first</span>
</Example>,
<Example className="second" children={<span>Child in second</span>} />
],
document.getElementById("root")
);
<!-- language: lang-css -->
.first {
color: green;
}
.second {
color: blue;
}
<!-- language: lang-html -->
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<!-- end snippet -->
Spread notation is handy not only for that use case, but for creating a new object with most (or all) of the properties of an existing object — which comes up a lot when you're updating state, since you can't modify state directly:
this.setState(prevState => {
return {foo: {...prevState.foo, a: "updated"}};
});
That replaces `this.state.foo` with a new object with all the same properties as `foo` except the `a` property, which becomes `"updated"`:
<!-- begin snippet: js hide: true console: true babel: false -->
<!-- language: lang-js -->
const obj = {
foo: {
a: 1,
b: 2,
c: 3
}
};
console.log("original", obj.foo);
// Creates a NEW object and assigns it to `obj.foo`
obj.foo = {...obj.foo, a: "updated"};
console.log("updated", obj.foo);
<!-- language: lang-css -->
.as-console-wrapper {
max-height: 100% !important;
}
<!-- end snippet -->
[1]: https://reactjs.org/docs/jsx-in-depth.html#children-in-jsx