This is a small list of common techniques used in React to compose and enhance components. Feel free to create Pull Requests with further techniques or fixes.
Elements can be passed as children into components.
const Layout = ({ children, theme }) => (
<div className={`theme-${theme}`}>
<main>{children}</main>
</div>
);
const Content = () => (
<div>Some fancy content</div>
);
ReactDOM.render(
<Layout theme='dark'>
<Content />
</Layout>
, containerEl);
Children are not limited to being elements. You can pass basically anything, including plain objects.
const Layout = ({ children, theme }) => (
<div className={`theme-${theme}`}>
<header>{children.header}</header>
<main>{children.content}</main>
<footer>{children.footer}</footer>
</div>
);
const Header = () => (
<h5>Header title</h5>
);
const Footer = () => (
<em>footer note</em>
);
const Content = () => (
<div>Some fancy content</div>
);
ReactDOM.render(
<Layout theme='dark'>
{{
header: <Header />,
content: <Content />,
footer: <Footer />
}}
</Layout>
, containerEl);
Elements can also be passed in using props.
const Layout = ({ header, content, footer, theme }) => (
<div className={`theme-${theme}`}>
<header>{header}</header>
<main>{content}</main>
<footer>{footer}</footer>
</div>
);
const Header = () => (
<h5>Header title</h5>
);
const Footer = () => (
<em>footer note</em>
);
const Content = () => (
<div>Some fancy content</div>
);
ReactDOM.render(
<Layout
theme='dark'
header={<Header />}
content={<Content />}
footer={<Footer />}
/>
, containerEl);
It's possible to enhance certain elements with additional props using
React.cloneElement
.
const Layout = ({ children, theme }) => (
<div className={`theme-${theme}`}>
<main>{React.cloneElement(children, { theme })}</main>
</div>
);
const Content = ({ theme }) => (
<div>Currently using this theme: {theme}</div>
);
ReactDOM.render(
<Layout theme='dark'>
<Content />
</Layout>
, containerEl);
Like elements, you can also pass components in using props.
const Layout = ({ children, contentComponent, theme }) => {
const ContentComponent = contentComponent;
return (
<div className={`theme-${theme}`}>
<main><ContentComponent theme={theme} /></main>
</div>
);
};
const Content = ({ theme }) => (
<div>Currently using this theme: {theme}</div>
);
ReactDOM.render(
<Layout
theme='dark'
contentComponent={Content}
/>
, containerEl);
Higher Order Components are functions which get a component passed in as argument and return a new component.
function createComponentWithDefaultProps(WrappedComponent, defaultProps) {
return (props) => (
<WrappedComponent {...defaultProps} {...props} />
);
}
const Layout = ({ children, theme }) => (
<div className={`theme-${theme}`}>
<main>{children}</main>
</div>
);
const DarkLayout = createComponentWithDefaultProps(Layout, { theme: 'dark' });
ReactDOM.render(
<DarkLayout>Some content</DarkLayout>
, containerEl);
Since children can be anything, they can also be functions.
class FetchTheme extends React.Component {
constructor() {
super();
this.state = {
theme: null
};
}
componentDidMount() {
fetch('/api/currentTheme')
.then((res) => res.text())
.then(((theme) => {
this.setState({ theme });
}));
}
render() {
const { children } = this.props;
const { theme } = this.state;
return theme ? children(theme) : null;
}
}
const Layout = ({ children, theme }) => (
<div className={`theme-${theme}`}>
<main>{children}</main>
</div>
);
ReactDOM.render(
<FetchTheme>
{
(theme) => (
<Layout theme={theme}>Some content</Layout>
)
}
</FetchTheme>
, containerEl);
Copyright (c) 2017 Simon Kusterer Licensed under the MIT license.