After implementing my first compound component in React, I’m officially addicted to this pattern. As the self-proclaimed expert on the matter (actually I learned from Ryan Florence and his talk on compound components), I’m going to teach you how to learn the best advanced React pattern out there in a few simple steps. Why? Because you deserve a better codebase!
At this point you might be thinking, who is this guy? He’s not Kent C. Dodds, who wrote the course on compound components. He’s not our beloved React prophet Dan Abramov. Well, my response to you is you’re correct!
You want to make the JSX markup easy to read by grouping related components. The approach is extensible as adding another step or button is as simple as adding another component to the relevant component group. The logic that powers the fundamental components at the bottom will come from the component above. StepList and ButtonList make up the first level of the related components.
A Step renders a given component if its the active step. Previous goes back a step if possible. Next moves forward a step if possible. Submit displays the submit message but only if its the last step. StepList and ButtonList pass down props to that determine which buttons to render on a given step and what step is active.
From here you think about what props each container component needs. StepList needs to determine the current step to present to the user. Use a current step prop. ButtonList shows the Previous, Next, and Submit buttons on certain steps. An active step and total steps help determine when to show each button. You need a submit function because this is a form. Now that you have the props, you’re done! Well, not exactly.
Don’t do this! We want to pass props indirectly.
With you props in mind, you might be tempted to write your props directly on your components like you see above but there is a cleaner way to pass props. The better way is to pass your props indirectly. How you ask? The React API has a couple useful methods you can use to create new components from existing ones. That’s where React.Children and React.cloneElement will become useful.
The best part of React is that a component is a regular objects. As with any object, you can manipulate them to pass around different props and functionality without having to annotate JSX components directly. React.Children will allow you to iterate over the children of a component. React.cloneElement will allow you to create new component with additional props from an existing component element.
Here you iterate the children in FormWizard using React.Children. As you iterate, use React.cloneElement to create a new component with the desired props you want to pass down the component tree.
The advancement functions, onNextStep and onPreviousStep, are used by Next and Previous buttons. The handleSubmit is used by Submit. We add these props to the new ButtonList component to pass downward. The activeStepIndex prop helps both the Step components and form buttons determine if they should render.
The new Step component will get an isActive prop from StepList to know when to render a step. The functions and state props in the ButtonList component go to the corresponding buttons that need them. Our form hides the previous button on the first step, hides the next button on the last step, and shows the submit button on the last step. Outside these cases the buttons are visible.
Finally, use the props passed to the base components to determine what should be rendered. See, simple! Sorta. I admit there is a lot to wrap your head around. But here’s the best part, Oprah and I are both Aquarius (what’s the plural of Aquarius? Aquarii?) therefore: you get a demo, you get a demo, everybody gets a demo! Here is a
of the guide.With React 16.3 you could use the Context API to make the FormWizard even more flexible in regards to props. Since your application is only a few levels deep you should follow the advice given in the docs. Use Context when you are passing down the same data to many components, at multiple levels.
If you enjoyed this dope techno guide then join the Dope Technophiles newsletter where we share the dope shit we’re building. Now go forth and spread the word of compound components. Share this post with a friend to make them dope!
Cheers!May 12th, 2018
👋🏽Hi! I’m Steven Natera. Follow me on Twitter @StevenNatera. I’m actively involved in the open source community, specifically GatsbyJS. I like writing about code, startups, React and Kubernetes.