Reputation: 7217
I'm prefacing this with the fact I'm VERY new to ReactJs and probably trying to work out something quite basic.
I have this code with a custom piece of HTML:
Sample Component
const Sample = ({ title, children }) => {
return (
<div class="panel">
<div class="title">
{title}
</div>
<div class="body">
{children}
</div>
</div>
);
};
Side question - whats the correct name for the above? A fragment? It doesn't look to be a "component" but just learning the naming conventions for React too
Utilise Component
export default class ExampleComponent extends Component {
render() {
return <div class="page-body">
<div class="row">
<h1> Page 1 </h1>
<Sample title={<h1>Some title!</h1>}>
<p>This is my sample body!</p>
</Sample>
</div>
</div>
}
}
Desired way to utilise Sample Component
export default class ExampleComponent extends Component {
render() {
return <div class="page-body">
<div class="row">
<h1> Page 1 </h1>
<Sample title="Some title!">
<Sample.Title>
<h1>This is my new way to do a title</h1>
</Sample.Title>
<Sample.Body>
<p>This is my sample body!</p>
</Sample.Body>
</Sample>
</div>
</div>
}
}
I've used this type of approach before with components others have created but want to do it myself now and finding it hard to get a simple example to do this.
Thanks in advance for any pointers!
Upvotes: 16
Views: 34640
Reputation: 19947
The Children
utils suit can be helpful for your scenario.
import { Children } from 'react'
const Sample = ({ title, children }) => {
let _body, _title
Children.forEach(children, child => {
if (child.type === SampleTitle) {
return _title = child
}
if (child.type === SampleBody) {
return _body = child
}
})
if (!_title) _title = <div className='title'>{title}</div>
if (!_body) _body = <div className='title'>{children}</div>
return (
<div className='panel'>
{_title}
{_body}
</div>
)
}
const SampleTitle = ({ children }) => <div className='title'>{children}</div>
const SampleBody = ({ children }) => <div className='body'>{children}</div>
Sampe.Title = SampleTitle
Sample.Body = SampleBody
Now you can use Sample in multiple ways:
<Sample title="my title">
<div>my body</div>
</Sample>
<Sample title="my title">
<Sample.Body>my body</Sample.Body>
</Sample>
<Sample title="my fallback title">
<Sample.Title>my overriding title</Sample.Title>
<Sample.Body>my body</Sample.Body>
</Sample>
Upvotes: 16
Reputation: 6446
I think what you want is called JSX Namespacing? Either way, you can instantiate Sample, and then add more components as properties of Sample (view it as an object):
import React from "react"
const Sample = ({ children }) => (
<div className="panel">
{children}
</div>
)
Sample.Title = (props) => <div className="title">{props.children}</div>
Sample.Body = (props) => <div className="body">{props.children}</div>
export default Sample
Note: React uses className
rather than class
since we are using JSX.
Upvotes: 24
Reputation: 16309
In that case you just have to extract the relevant containers into their own components:
const Sample = ({children }) => (
<div className="panel">{children}</div>
);
const Title = ({children}) => (
<div className="title">{children}</div>
);
const Body = ({children}) => (
<div className="body">{children}</div>
);
Sample.Title = Title;
Sample.Body = Body;
Also note that the correct prop for a css class is className
.
Upvotes: 3