Write Compound Components

InstructorKent C. Dodds

Share this video with your friends

Send Tweet

Compound component gives more rendering control to the user. The functionality of the component stays intact while how it looks and the order of the children can be changed at will. We get this functionality by using the special React.Children.map function to map over the children given to our <Toggle/> component. We map over the children to pass the on state as a prop to its children. We move the visual pieces of the component out into function components and add them as static properties to <Toggle/>.

This lesson is a Community Resource

A Community Resource means that it’s free to access for all. The instructor of this lesson requested it to be open to the public.

Tim Anashev
Tim Anashev
~ 3 years ago

Why we need clone children? Can we pass just this.props.children instead of cloning elements?

Kent C. Dodds
Kent C. Dodds(instructor)
~ 3 years ago

Give it a try πŸ˜‰

You'll find that the components you render don't have the necessary props. We need to pass the props somehow, but we only have access to those props from within our toggle component. So our toggle component is responsible for passing those props in a way that implicit to users.

Jorge Alvarez
Jorge Alvarez
~ 3 years ago

I don't understand why you are passing the arguments of a function as an object, like in:

function toggleOn({on, children}) { ... }
James McAllister
James McAllister
~ 3 years ago

Thats just destructing the props.

same as

function toggleOn(props) { 
const {on, children} = props
...
}
` 
Pavel
Pavel
~ 3 years ago

Is it a good practice to pass 'toggle' method to all the children, since we use this method with one of them only? Or it's done just on a demonstration purpose?

Kent C. Dodds
Kent C. Dodds(instructor)
~ 3 years ago

Hi Pavel. The thing is that there's no reasonable way to know which child needs it and which doesn't. I mean, you could look at the type property of the child and that would allow you to know, but someone could make a custom component that expects to get the prop as well. No harm passing it to all of them πŸ‘Œ

Nick Renford
Nick Renford
~ 3 years ago

What is the purpose of adding

  static On = ToggleOn
  static Off = ToggleOff
  static Button = ToggleButton

to the Toggle component? Where are these properties referenced?

Paolo
Paolo
~ 3 years ago

Hi Kent, What about adding a component that is neither a Toggle.On, Toggle.Off, or Toggle.Button? Should there be some sort of error checking? When I think of compound components, I think of HTML's select and option tags. You can't add a div inside a select tag. Also, an option tag cannot be outside of a select tag. Is there ways to control that?

Kent C. Dodds
Kent C. Dodds(instructor)
~ 3 years ago

Sure! You could definitely add validation. See here: https://codesandbox.io/s/v835q7o193

You'll see I added an array of the valid types and then I check child.type against that array and log an error if the child's type is invalid. :)

Paolo
Paolo
~ 3 years ago

Thank you so much Kent! That was awesome for you taking the time to create a code sandbox example! Loving the tutorial!

0 plusX
0 plusX
~ 3 years ago

Can we use a Context API instead of cloning-and-assigning props? This will allow to pick values at any level of the tree. For example, if user adds containers as first level, and places Toggle.On inside these containers. Edit: Ahh... Its in the next lesson. Sorry...

Jan Borchers
Jan Borchers
~ 3 years ago

To follow up on Artyom's comment: I don't understand why we need to clone the children either. It works fine without:

https://codesandbox.io/s/y2p7or1509

Kent C. Dodds
Kent C. Dodds(instructor)
~ 3 years ago

I'm afraid that doesn't work. When you do: <Toggle.On /> that creates a react element which is an object, which is why you get this error in that codesandbox:

Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object.
Jan Borchers
Jan Borchers
~ 3 years ago

argh, ignore me, I hadn't saved the editor, that's why it was still working πŸ˜‘πŸ˜‘πŸ˜‘

Edwin
Edwin
~ 3 years ago

I was trying to follow everything you did here in my environment which is using create-react-app. but I just don't understand how the Switch cab be looked like that. When I'd pasted your Switch code and CSS you provide, it just a checkbox and empty value button. am I missing something?

Johnny Zabala
Johnny Zabala
~ 3 years ago

Hi Edwin maybe you can try to download the codesanbox that Kent created and compare it with yours: https://codesandbox.io/s/v835q7o193

I downloaded, installed the dependencies and run it and it looks great.

Tony Brown
Tony Brown
~ 3 years ago

Very cool, I’m digging the the new api