This is a small list of common techniques used in React to compose and enhance components.
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);
Class Component | Stateless Component |
---|---|
State | Everywhere else |
Refs | |
Lifecycle methods | |
Child functions (for performance) |
Container Component(Smart, Stateful, Controller View) | Presentation Component(Dumb, Stateless, View) |
---|---|
Little to no markup | Nearly all markup |
Focus on how things work | Focus on how things looks |
Pass data and actions down/subscribe to Redux State | Receive data and actions via props |
Knows about Redux | Doesn’t know about Redux |
Often stateful | Typically functional components |
Dispatch Redux actions | Invoke callbacks on props |
Generated by react-redux | Written by hand |
”When you notice that some components don’t use props they receive but merely forward them down…it’s a good time to introduce some container components.” ~Dan Abramov
Flux | Redux |
---|---|
Stores contain state and change logic | Store and change logic are separate |
Multiple stores | One store |
Flat and disconnected stores | Single store with hierarchical reducers |
Singleton dispatcher | No dispatcher |
React components subscribe to stores | Container components utilize connect |
State is mutated | State is immutable |
- Immutable Store
- Actions trigger changes
- Reducers return updated state
ES6 | ES5 | Libraries |
---|---|---|
Object.assign | Lodash merge | react-addons-update |
Spead operator | Lodash extend | Immutable.js |
Object-assign |