There are many ways of authoring components in React, and doing it right might not be that easy, especially when components get more complex. In this talk, you will learn how to build future-proof React components. We will cover two different approaches to building components - Composition and Configuration, to build the same component using both approaches and explore their advantages and disadvantages.
Composition vs Configuration: How to Build Flexible, Resilient and Future-proof Components
React Summit 2022
Hey today, I'm going to talk about how to build flexible resilient and future-proof components in react. I'm going to cover two different approaches to building components composition and configuration. But first, let me tell you a bit about myself. My name is Thomas Finley and I'm a full stack weapon mobile developer with 10 years of programming experience. I co-owner of Hindi webtech as well as a mentor and consultant at good Mentor IO platform. Besides that I'm the author of react drone Enterprise and view the road to Enterprise books. I also write articles for taleric and the auto Enterprise blocks. Okay. That's enough about myself now. Components so let's be honest building future proof components is not easy. I mean well if you haven't component like this, right, it's very simple. So for this example, I will use an alert component. So for example, if you would want to have an Allied component that would display this key pallet message, but we could do something like this, right we could receive text intrusion as props. Have some this was difficult styles. And then render what was passed right and here's how we could use it. Just use the light component and pass the text message inside of it. So obviously that's very simple. But the problem with building good components is that as we need to add more functionality the complexity just Grows Right and the code is becoming much harder to maintain and extent. So what if we would want to add more features to this alert component? Let's say we want to add a header as well. So we could receive a header as a prop. And if one was passed we would display it, right. As shown here in the example. So for instance on the right side, we have one alert just with the text message and the other one with both the outlet header and the text message. So that's quite simple Style. Now what about variance? Well, I guess we could again add another prop like variant, right? And then based on that prop and whatever the variant was selected we could add a prepaid Styles. So for instance, we could support the Vans like success danger warning or info as you can see on the right side. And that's how it that's how we would use it. We'll just pass header and variant probes and some text inside. Okay. So what about adding maybe an icon? Well again another prop. icon if it was passed. And we found a supported icon then we can render it. Simple, isn't it? And that's why we could use it. So basically by default the icon could be displayed on the left side. But what if you would want to actually be able to specify on which side we wanted to display the icon like maybe not on the left but on the right? Well, guess what? another prop So for instance, we could pass a problem like icon position right by default we could set it to left. And then if for instance it was right, we could specify some class right? That'll be added on the alert container. Note that I'm using Talent here for classes. And yeah, that's how we would use it just more props. So That was the configuration approach. Right? Basically whenever we just need to add more functionality, we have more props, but well that can be problematic at some point because the thing is But before every new variant and functionality, we need to add more and more props and conditional logic, right? And sometimes it might just become much harder to like, you know, overwrite the already defined logic inside of the component or even extended. So that's not really the best the configuration approach makes it much harder. So and sometimes even component can be extended. We might need to build a new version of it. Well as for pros, well, obviously a configuration approach. Well a component built with a configuration approach is quick and easy to use right because you only need to know about what props are really available and what you need to provide. And so yeah, basically different functionality in visual events can be controlled by props and that's it. And another benefit of that is that it's much harder to diverge from the design system, right? Because the thing is you only can provide props in that set. You can do read anything else with it. So well this keeps the UI in Behavior consistent. but yeah, like I mentioned the problem is that we can't easily extend configuration. Build components or override it. So what can we do? Well, I mean we could obviously Provide maybe props. Like let's say you render icon render header, you know render body and so on and so on but again more props, it will be just more messy. So be more conditional logic inside of the Allied component. So instead of trying to configure everything. How about We'll use a different approach composition. So in this example, we have one free components first the art wrapper then alet content and Allied body and to the other body. We pass the text message. I know three components just for the text message isn't much but stay with me. So how it could look like basically the alert components obviously do the receive some probes. Then it would render a diff with a puppet Styles and children, right? So in this case, the children will be the alert content and alert body. Then we have the other content as we see it's very similar to the alert component because again, you just receives the props. And has a diff with some styles. And actually well the same will apply to other body. I know there's a bit of repetition and we have a few components already, but it's worth it at the end. Just remember that it's a contract example. So yeah, that's how it that's how we use it. Now if we would want to add let's say an alert header. Well, we don't need other prop. We just add another component like alert header basically, so all these components are just building blocks which we use to compose the functionality. And what about Let's see. So first up again as Heather in this case also is very similar to other components. You just receive the props renders the diff with correct styles. And then finally the children. Now next what if we would want to have variance? Well, I guess maybe we could actually pass that one prop to download component. Of course, we could also create a component for it. But for this example, this will do. So with passive variant probe to the alert. But now the thing is that we can't compose the components right to build the alert functionality. But the thing is that we can also use a not only the building blocks the components that we build specifical for the alert, but we can actually just use any custom markup we want. If we really wanted it, we could not use any of this building blocks just the alert component. So how do we provide a variant tool? No, all these other components like Iris header and Allied body because they need to know what's the variant? Because they need to have appropriate Styles like for instance the header and body for the success variant have a dark green text while the background for the alert is light. And also we have the border on the left that is dark. So what we can do is we use context context API to basically provide the variant that was specified to all the components in the component tree So in this case, we receive variant as a prop. And then we pass it to the variant context provider, right? And besides that we also use it to specify a perfect classes. for the alert component now, let's have a look how we can build this variant context provider. So I've used a little context actually helper. We'll get to it in a moment. Basically. It just returns a custom hook that will consume the context and the context itself. And as you can see on my five here, they use variant context is exported so that it can be consumed in other components. And then in the variant context provider, we basically just render the provider and pass the variance to it. That's it. Next and so here we have the context Factory. Basically, it creates the context create the consumer and return them. Now Alice header. Yes, so we need to know update the alert header and other body components because they now also need access to the variant. So we import this variant context hook we consume the context. And then we use it to apply a prepaid styles. And we do the same in the alert body again consume the context. And apply the styles. Okay. Next so we have alert components with variance in icons, right? So if we wanted to add an icon again another building block, right we can just use a component. That was already built as part of the let's say no all the alert components and pass the specific icon or if you would want we could even add some custom markup for it. Now how would we use it? so first we can have a icon config map. We're basically the icon is mapped to let's say sfg icons or whatever the component you would want to use. Next we use the icon prop to retrieve one of the icons that are supported. and if we have one then we render the Market Besides that we also consume the variant context. So we can alter prepared slice to the icon. For example, correct colors. Like in our example the success icon obviously will be green while warning icon will be orange. So as per positions, well, basically we could move the alert icon component to the bottom and we could add some styles to it, right? So for example in this case the alert icon because it was moved to the bottom. You will be rendered after the alert content. So it would be on the right side. And then we for instance can add some margin left Auto with some right pad with some margin right value to have it positioned on the right side. As you can see here. So that was the composition approach. So obviously the composition approaches extremely flexible, right? Because you just basically use the components which are building blocks. to compose the functionality If you for instance need something more custom you can just create new markup right custom markup or you can add more building blocks and that's that. So yeah, that's why composition approach is really flexible. And it's not hard to you know, extend functionality or and you don't really even have to override anything right because you just compose everything. So yeah, it is very easy to create different functionality in the UI variance. with composition approach However, there are some cons to this approach right because obviously you need to compose the building blocks yourself right to create this file function fully functioning component or feature. Because of that you need to know how the building blocks work what they do and how they should be composed. This isn't the case when using the configuration approach because with the configuration approach you basically just need to know what probes you're supposed to provide and that's it. In the configuration approach we see the component just takes care of everything right under the hood, but you don't know you might not know what's going on there. You just need to know the props and what values in the past and that's that why would the composition approach you do need to know what the building blocks are doing and how they are how they should be used. And well obviously another cone is that it does take more time and code right to create the same thing because again, you need to compose the building blocks yourself. And another disadvantage is that it's much easier to diverge from the design system and shipping consistent UI and behavior. Well, obviously because you basically can compose the breathing blocks, you know, however you want. Right? So it'll be easy to make mistakes and shipping consistent you I just basically by providing wrong classes or are there in the building blocks in the wrong way. This isn't the case with the configuration approach. Because again, you just provide props and that's it. So again, both approaches have the processing cost right? So question is when should we use which one? well technically why not both right because what we can do Is first use the composition approach to basically build the well create the components that are the building blocks, right? And then we can use them to create a configuration configured component. Like here we have an example. Again, like we did in the configuration project example, we receive a number of props right for the alert then. We have the base valid component. And which basically accepts the variant and class name? Then we also have the alert icon if the iPhone was passed any prendered. and other content where if they had there was passed and alicator component will be rendered and if the text or children were passed then other body will be rendered with And yeah, that's how you can combine composition and configuration approaches to basically build components. So most of the time just you can use a configured component, but if you need more flexibility, right then you have this building blocks available for you. So in summary composition approach offers more flexibility, but it does require more knowledge of how to compose the building blocks right how they work. On the other hand configuration approach is less flexible, but this simpler to use and makes it easier to stick to the design system. But yeah, we can combine both approaches to get the best of both worlds. So you can find code examples for this presentation in this GitHub repo. What's more if you'd like to learn more about Advanced patterns best practices techniques for many crucial content that Concepts? Such as local and Global State Management scalable project architecture performance optimization managing apis testing and much much more. You should definitely check out reactor Auto Enterprise. And yeah, if you'd like to get in touch, you can find me on Twitter LinkedIn code mentor and 02 Enterprise platform as well. That's it for today. I hope you I hope you enjoyed the talk and have a great day.