You can't feel the power quite yet, but we're about to power up our rendering skills by passing a function as a child:
<React.Fragment>
{() => {}}
</React.Fragment>
Blep.
Well, that wasn't very exciting. Not yet at least. What we need first is an idea. Let's build a share toolbar! It will be quite simple. We're going to have a row of icons: One to share to Facebook; one to share to Twitter; one to send via email; and one to copy a permalink. Sounds pretty simple. I've seen these on many sites.
function ShareToolbar(props) {
return (
<div>
<a href="javascript:">Facebook</a>
<a href="javascript:">Twitter</a>
<a href="javascript:">Email</a>
<a href="javascript:">Permalink</a>
</div>
);
}
It's looking a little like something now. Not exactly anything special. But, I want to do a little bit more here. I want to be able to style each of the links. Possibly turn them into social icon buttons with an SVG icon. I may want them to have calculated hyperlinks. I also want to create a "drawer" for the permalink, so we can visually see a short url next to the cute buttons.
const Item = (props) =>
<Item onClick={props.onClick} href={props.href}>{props.children}</Item>;
const Button = (props) =>
<Button>{props.children}</Button>;
const Drawer = (props) =>
props.isOpen ? <Drawer>{props.children}</Drawer> : null;
function ShareToolbar(props) {
return (
<React.Fragment>
{props.children ? props.children({
Item,
Button,
Drawer
}) : null}
</React.Fragment>
);
}
export default ShareToolbar
Well that got complex real fast. But, at least it's readable! (I hope). We're doing exactly what we did in the first example, however, instead of returning an empty object, or in the second example, where we return JSX, we're calling the children prop as a function (if it exists)
Why does this sentence almost not make sense?
calling the children prop as a function
That's probably because it's just difficult at first to visualize, until we develop it from an example. Let's go the opposite direction and instead design how we want to use the component:
<ShareToolbar>
{({ Item, Button, Drawer }) => {
return (
<Toolbar>
<Item href='https://facebook.com'>
<Button>
<Icon name='facebook' />
</Button>
</Item>
<Item href='https://twitter.com'>
<Button>
<Icon name='twitter' />
</Button>
</Item>
<Item href='https://gmail.com'>
<Button>
<Icon name='mail' />
</Button>
</Item>
<Item onClick={() => {
copy('https://google.com');
alert('copied to clipboard.');
}}>
<Button>
<Icon name='link' />
</Button>
<Drawer isOpen>
https://google.com
</Drawer>
</Item>
</Toolbar>
);
}}
</ShareToolbar>
This reads much clearer (I hope). What we're looking at is psuedo code, however, with the power of styled-components, the naming conventions can actually remain the same. They're just divs after all.
{({ Item, Button, Drawer }) => { // the render callback, `ShareToolbar.children`
...
}}
Remember how we were calling props.children
as a function? This is that function, being called. It's just squished in-between the ShareToolbar
component.
What makes this pattern powerful, is that it allows us to abstract the visual hierarchy of the component and provide the ability to dynamically compose the view how we'd like to render it, versus being made to render in one specific way.
You'll notice this pattern starts to make more sense when it comes to abstracting the view layer from the data layer, in which data is passed as values in the render callback, rather than components. You can read more about this in my next post, Using render callbacks to connect non-connected components.
This article was first published on Codementor https://www.codementor.io/moimikey/power-up-your-renders-with-render-callbacks-mb96thj33
Top comments (2)
Final Flash!!!
:)
wooooooooop
I just build a site and I am looking for the render blocking resources solution? Do you know about how to eliminate them. render blockingt