Sunday, February 14, 2021

Compound Components (in React)

Components are a great way of reusing the same code, making it easier for a  website to have a consistent look and easier to maintain.

But what if  we have components nested inside other components, like a book with multiple pages? Our first thought might be to a have a <Book /> component and in it we'd put the logic and which <Pages> that will be rendered. This is fine, but it's less flexible that using compound components pattern, like the following.

Let's consider a <Book> component which is a container that handles the logic and accepts <Pages> components as childs, like this:

<Book>
    <Page1 />
    <Page2 />
    ...
</Book>

The book container for this example will have a state to keep track of the current Page, an input box to select page, and will render a copy(clone) of the child components.

It will look like this:

const Book = ({children}) => {
  const [page, setPage] = React.useState(0);
 
  return <div>
    {React.Children.map(children, (child, index) => {
      var toRender = index == page;
      
      return React.cloneElement(child, { toRender});
    })}
    <p>Jump to page:</p>
    <input type="text" onChange={(e) => setPage(e.target.value)} />
  </div>
}

Then we can add any number of child components and they will automatically render if in the book is in the right page.

const Page1 = ({ toRender}) => (toRender ? "Simple text" : null);
const Page2 = ({ toRender}) => (toRender ? (<div><h1>Hello World strikes back</h1><p>Once upon a time on a far away computer there was a 'Hello World' example...</p></div>) : null);

And have fun adding more pages to your new book.

To sum, compound components is great pattern that handles logic in an elegant way without having to worry (much) on which and how many childrens are passed in.

No comments:

Post a Comment