Composition vs Configuration: How to Build Flexible, Resilient and Future-proof Components

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.

Rate this content
Bookmark
Video Summary and Transcription
The video explores the concept of building flexible, resilient, and future-proof components in React using two main approaches: composition and configuration. The composition approach is highlighted for its flexibility, allowing developers to use smaller building blocks to create complex components. This method is ideal for those looking to achieve component flexibility without excessive conditional logic, particularly in scenarios like developing an alert component with customizable headers, variants, and icons. The configuration approach, on the other hand, is noted for its simplicity and consistency, making it easier to use but harder to extend over time. The video emphasizes that while configuration can become cumbersome with added props and conditional logic, combining both approaches can provide the best of both worlds. Developers can use composition to create basic building blocks and then configure these for more complex applications, thus maintaining flexibility and easing component use. The video also touches on the use of the Context API for managing styles and variants, and discusses the pros and cons of both approaches, noting the importance of understanding component vs configuration to build robust React applications.

This talk has been presented at React Summit 2022, check out the latest edition of this React Conference.

FAQ

Tomasz Findly is a full-stack web and mobile developer with 10 years of programming experience. He is a co-owner of Findly WebTech, a mentor and consultant at CodeMentor.io, and the author of 'React, the Road to Enterprise' and 'Viewed the Road to Enterprise' books.

You can find Tomasz Findly on Twitter, LinkedIn, CodeMentor, and the Road to Enterprise platform.

The configuration approach involves adding more props to a component to add more functionality. This makes the component easier to use but harder to extend and maintain over time.

Pros: Quick and easy to use, keeps UI and behavior consistent. Cons: Hard to extend or override, more props lead to more conditional logic and complexity.

The composition approach involves using smaller building blocks (components) to compose the functionality of a larger component. This makes the component more flexible and easier to extend.

Pros: Extremely flexible, easy to extend functionality. Cons: Requires more knowledge of building blocks, takes more time and code, easier to diverge from the design system.

Tomasz Findly recommends checking out 'React.io's Road to Enterprise' for learning advanced patterns, best practices, and techniques for crucial concepts like state management, scalable project architecture, performance optimization, managing APIs, and testing.

Tomasz Findly uses an alert component as an example to explain building future-proof components in React.

Tomasz Findly discusses two approaches to building components in React: composition and configuration.

You can use the composition approach to build smaller building blocks and then combine them to create a configured component. This way, you get the flexibility of composition and the ease of use of configuration.

1. Building Flexible and Resilient React Components#

Short description:

Today, I will discuss how to build flexible, resilient, and future-proof components in React. We will explore two approaches: composition and configuration. Building future-proof components can be challenging as the complexity grows. Adding features like headers, variants, and icons requires careful consideration of props and styles.

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 Tomasz Findly and I'm a full-stack web and mobile developer with 10 years of programming experience. I'm a co-owner of Findly WebTech, as well as a mentor and consultant at CodeMentor.io platform. Besides that, I'm the author of React, the Road to Enterprise and Viewed the Road to Enterprise books. I also write articles for Telerik and the Road to Enterprise blogs.

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 have a component like this, it's very simple. So for this example, I will use an alert component. So for example, if you would want to have an alert component that would display a basic alert message, well, we could do something like this, right? We could receive text entries as props, have some divs with styles, and then render what was passed, right? And here's how we could use it. Just use the alert 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? The code is becoming much harder to maintain and extend. So what if we would want to add more features to this alert component? Let's say we just 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 and the other one with both the alert header and the text message.

So what about variants? 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 appropriate styles. So, for instance, we could support variants like success, danger, warning, or info, as you can see on the right side. And that's how we would use it. Just pass header and variant props and some text inside.

So what about adding, maybe, an icon? Well, again, another prop, like icon. If it was passed, and we found a supported icon, then we can render it. Simple, isn't it? And that's how we could use it. So, basically, by default, the icon could be displayed on the left. But what if we want to specify on which side we want it to be displayed? Like, maybe not on the left, but on the right? Well, guess what? Another prop! So, for instance, we could pass a prop like iconPosition, right? By default we could set it to left. And then, if, for instance, it was right, we could specify some classes, right, that would be added on the alert container. Note that I'm using Tailwind here for classes.

2. Using Composition for Flexibility#

Short description:

The configuration approach can become problematic when adding more functionality requires adding more props and conditional logic. It becomes harder to extend or overwrite the component's logic. On the other hand, composition offers a different approach. By using multiple components and passing props, we can achieve flexibility without excessive conditional logic. In the example, the alert component is composed of the alert wrapper, alert content, and alert body components, allowing for more control and easier extension.

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 add more props. But, well, that can be problematic at some point. Because the thing is, for 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 overwrite the already defined logic inside of a component or even extend it. So, that's not really the best. The configuration approach makes it much harder. So, sometimes if a component can't 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. So, yeah. Basically different functionality and visual variants can be controlled via 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 and that's it. You can't do really anything else with it. So, well, this keeps the UI and behavior consistent.

But, yeah, like I mentioned the problem is that we can't easily extend the configuration build component or override it. So, what can we do? Well, I mean we could obviously provide maybe props like, let's say, a render icon, render header, you know, render body and so on and so on. But again, more props would be just more messy. So, there would be more conditional logic inside of the alert component. So, instead of trying to configure everything, how about we'll use a different approach, composition.

So, in this example, we have three components. First, the alert wrapper, then alert content, and alert body. And to the alert body, we pass the text message. I know three components just for the text message is a bit much, but stay with me. So, how it could look like? Basically, the alert component, obviously, it would receive some props. Then it would render a div with appropriate styles and children, right? So, in this case, the children would be the alert content and alert body. Then we have the alert content. As you see, it's very similar to the alert component. Because, again, it just receives the props. And has a div with some styles. And actually, well, the same will apply to alert body. I know there's a bit of repetition, and we have a few of the components already, but it's worth it at the end.

3. Using Context API for Variant Styling#

Short description:

In this example, we can use different components to build the alert functionality, including custom markup. To provide variants to components like alertHeader and alertBody, we can use the context API. The variant is passed as a prop to the variant context provider, which then provides it to all components in the component tree. This allows for appropriate styling and class specification for the alert component. The context factory creates the context and consumer for easy consumption in other components.

Just remember that this is a contract example. So, yeah, that's how we use it. Now, if we would want to add, let's say an alert header, well, we don't need to add a 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 say, yeah, so first up again, our header in this case also is very similar to other components. It just receives 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 one prop to the alert component. Of course, we could also create a component for it. But for this example, this will do. So we'd pass a variant prop 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 not only the building blocks, the components that we build specifically 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 these building blocks, just the alert component.

So how do we provide a variant to all these other components like alertHeader and alertBody? Because they need to know what's the variant. Because they need to have appropriate styles. 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 the context API to 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. Besides that, we also use it to specify appropriate 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 factory 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, one line five here, the 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 variant to it. And that's it.

Next. So here we have the context factory, basically, it creates the context, creates the consumer and returns them. Now, alert header.

4. Using Variants and Icons#

Short description:

We update the alert header and body components to have access to the variant. We use the variant hook and consume the context to apply styles. Adding an icon is easy by using a pre-built component or custom markup. We use an icon config map to map icons to components. We consume the variant context to add appropriate styles to the icon. The composition approach is flexible and allows for easy extension of functionality. However, it requires composing building blocks and understanding their composition. The configuration approach only requires providing props.

Yes. So we need to now update the alert header and alert body component because they now also need access to the variant. So we import this variant hook, we consume the context and then we use it to apply appropriate styles. And we do the same in the alert body, again consume the context and apply the styles.

Okay. Next. So we have alert component with variants and 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, you know, all the alert components and pass a 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 an icon config map, where basically the icon is mapped to, let's say, sfg icons or whatever component you would want to use. Next, we use the icon prop to retrieve one of the icons that are supported. And then if we have one, then we render the markup for it. Besides that, we also consume the variant context so we can add appropriate styles 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 for positions, basically, we could move the alert icon component to the bottom and we could add some styles to it. For example, in this case, the alert icon, because it was moved to the bottom, it 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 approach is 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 a new markup, right, custom markup, or you can add more building blocks and that's that. So yeah, that's why the composition approach is really flexible. And it's not hard to, you know, extend functionality, or you don't even have to overwrite anything, right? Because you just compose everything. So, yeah, it is very easy to create different functionality and UI variants 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 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 props you're supposed to provide. And that's it. In the configuration approach, basically the component just takes care of everything, right, under the hood. Because you don't know...

5. Combining Composition and Configuration#

Short description:

The composition approach offers more flexibility but requires more knowledge of how to compose building blocks. The configuration approach is less flexible but simpler to use and helps maintain consistency. Both approaches can be combined to get the best of both worlds.

You might not know what's going on there. You just need to know the props and what values you need to pass. That's that. While with 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 con 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 ship inconsistent UI and behavior. Obviously, because you basically can compose the building blocks, you know, however you want, right. So it would be easier to make mistakes and ship inconsistent UI just, basically, by providing wrong classes or ordering 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 their pros and cons, right. So the 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 configure component, like here we have an example. Again, like we did in the configuration approach example, we receive a number of props, right, for the alert, then we have the baseline component, which basically accepts the variant and class name. Then we also have the alert icon. If the icon was passed, then it'll be rendered. And alert content, where if the header was passed, then alert component would be rendered. And if the text for children were passed, then alert body would be rendered. 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 these 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? And how they work. On the other hand, configuration approach is less flexible, but it is 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 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 React.io's Road to Enterprise. And if you'd like to get in touch, you can find me on Twitter, LinkedIn, CodeMentor, and the Road to Enterprise platform as well. Well, that's it for today.

Thomas Findlay
Thomas Findlay
17 min
21 Jun, 2022

Comments

Sign in or register to post your comment.

Check out more articles and videos

We constantly think of articles and videos that might spark Git people interest / skill us up or help building a stellar career

Scaling Up with Remix and Micro Frontends
Remix Conf Europe 2022Remix Conf Europe 2022
23 min
Scaling Up with Remix and Micro Frontends
Top Content
This talk discusses the usage of Microfrontends in Remix and introduces the Tiny Frontend library. Kazoo, a used car buying platform, follows a domain-driven design approach and encountered issues with granular slicing. Tiny Frontend aims to solve the slicing problem and promotes type safety and compatibility of shared dependencies. The speaker demonstrates how Tiny Frontend works with server-side rendering and how Remix can consume and update components without redeploying the app. The talk also explores the usage of micro frontends and the future support for Webpack Module Federation in Remix.
Design Systems: Walking the Line Between Flexibility and Consistency
React Advanced 2021React Advanced 2021
47 min
Design Systems: Walking the Line Between Flexibility and Consistency
Top Content
The Talk discusses the balance between flexibility and consistency in design systems. It explores the API design of the ActionList component and the customization options it offers. The use of component-based APIs and composability is emphasized for flexibility and customization. The Talk also touches on the ActionMenu component and the concept of building for people. The Q&A session covers topics such as component inclusion in design systems, API complexity, and the decision between creating a custom design system or using a component library.
Understanding React’s Fiber Architecture
React Advanced 2022React Advanced 2022
29 min
Understanding React’s Fiber Architecture
Top Content
This Talk explores React's internal jargon, specifically fiber, which is an internal unit of work for rendering and committing. Fibers facilitate efficient updates to elements and play a crucial role in the reconciliation process. The work loop, complete work, and commit phase are essential steps in the rendering process. Understanding React's internals can help with optimizing code and pull request reviews. React 18 introduces the work loop sync and async functions for concurrent features and prioritization. Fiber brings benefits like async rendering and the ability to discard work-in-progress trees, improving user experience.
Full Stack Components
Remix Conf Europe 2022Remix Conf Europe 2022
37 min
Full Stack Components
Top Content
RemixConf EU discussed full stack components and their benefits, such as marrying the backend and UI in the same file. The talk demonstrated the implementation of a combo box with search functionality using Remix and the Downshift library. It also highlighted the ease of creating resource routes in Remix and the importance of code organization and maintainability in full stack components. The speaker expressed gratitude towards the audience and discussed the future of Remix, including its acquisition by Shopify and the potential for collaboration with Hydrogen.
Towards a Standard Library for JavaScript Runtimes
Node Congress 2022Node Congress 2022
34 min
Towards a Standard Library for JavaScript Runtimes
Top Content
There is a need for a standard library of APIs for JavaScript runtimes, as there are currently multiple ways to perform fundamental tasks like base64 encoding. JavaScript runtimes have historically lacked a standard library, causing friction and difficulty for developers. The idea of a small core has both benefits and drawbacks, with some runtimes abusing it to limit innovation. There is a misalignment between Node and web browsers in terms of functionality and API standards. The proposal is to involve browser developers in conversations about API standardization and to create a common standard library for JavaScript runtimes.
Case Study: Building Accessible Reusable React Components at GitHub
React Summit 2024React Summit 2024
29 min
Case Study: Building Accessible Reusable React Components at GitHub
Watch video: Case Study: Building Accessible Reusable React Components at GitHub
The talk discusses building accessible React components and emphasizes the importance of using the correct HTML elements and ARIA roles for accessibility. It explains how to navigate and select options within a form and how to add supplementary text using Aria described by. The speaker also discusses the benefits of using conditional checkboxes and ARIA disabled to improve the UI. Additionally, the talk explores the role of JavaScript in web accessibility and provides recommendations for testing website accessibility.

Workshops on related topic

AI on Demand: Serverless AI
DevOps.js Conf 2024DevOps.js Conf 2024
163 min
AI on Demand: Serverless AI
Top Content
Featured WorkshopFree
Nathan Disidore
Nathan Disidore
In this workshop, we discuss the merits of serverless architecture and how it can be applied to the AI space. We'll explore options around building serverless RAG applications for a more lambda-esque approach to AI. Next, we'll get hands on and build a sample CRUD app that allows you to store information and query it using an LLM with Workers AI, Vectorize, D1, and Cloudflare Workers.
Build a Data-Rich Beautiful Dashboard With MUI X's Data Grid and Joy UI
React Summit 2023React Summit 2023
137 min
Build a Data-Rich Beautiful Dashboard With MUI X's Data Grid and Joy UI
Top Content
WorkshopFree
Sam Sycamore
Siriwat (Jun) Kunaporn
2 authors
Learn how to put MUI’s complete ecosystem to use to build a beautiful and sophisticated project management dashboard in a fraction of the time that it would take to construct it from scratch. In particular, we’ll see how to integrate the MUI X Data Grid with Joy UI, our newest component library and sibling to the industry-standard Material UI.
Table of contents:- Introducing our project and tools- App setup and package installation- Constructing the dashboard- Prototyping, styling, and themes - Joy UI features- Filtering, sorting, editing - Data Grid features- Conclusion, final thoughts, Q&A
Hands-on with AG Grid's React Data Grid
React Summit 2022React Summit 2022
147 min
Hands-on with AG Grid's React Data Grid
Top Content
WorkshopFree
Sean Landsman
Sean Landsman
Get started with AG Grid React Data Grid with a hands-on tutorial from the core team that will take you through the steps of creating your first grid, including how to configure the grid with simple properties and custom components. AG Grid community edition is completely free to use in commercial applications, so you'll learn a powerful tool that you can immediately add to your projects. You'll also discover how to load data into the grid and different ways to add custom rendering to the grid. By the end of the workshop, you will have created an AG Grid React Data Grid and customized with functional React components.- Getting started and installing AG Grid- Configuring sorting, filtering, pagination- Loading data into the grid- The grid API- Using hooks and functional components with AG Grid- Capabilities of the free community edition of AG Grid- Customizing the grid with React Components
Practice TypeScript Techniques Building React Server Components App
TypeScript Congress 2023TypeScript Congress 2023
131 min
Practice TypeScript Techniques Building React Server Components App
Workshop
Maurice de Beijer
Maurice de Beijer
In this hands-on workshop, Maurice will personally guide you through a series of exercises designed to empower you with a deep understanding of React Server Components and the power of TypeScript. Discover how to optimize your applications, improve performance, and unlock new possibilities.
 
During the workshop, you will:
- Maximize code maintainability and scalability with advanced TypeScript practices
- Unleash the performance benefits of React Server Components, surpassing traditional approaches
- Turbocharge your TypeScript with the power of Mapped Types
- Make your TypeScript types more secure with Opaque Types
- Explore the power of Template Literal Types when using Mapped Types
 
Maurice will virtually be by your side, offering comprehensive guidance and answering your questions as you navigate each exercise. By the end of the workshop, you'll have mastered React Server Components, armed with a newfound arsenal of TypeScript knowledge to supercharge your React applications.
 
Don't miss this opportunity to elevate your React expertise to new heights. Join our workshop and unlock the potential of React Server Components with TypeScript. Your apps will thank you.
High-performance Next.js
React Summit 2022React Summit 2022
50 min
High-performance Next.js
Workshop
Michele Riva
Michele Riva
Next.js is a compelling framework that makes many tasks effortless by providing many out-of-the-box solutions. But as soon as our app needs to scale, it is essential to maintain high performance without compromising maintenance and server costs. In this workshop, we will see how to analyze Next.js performances, resources usage, how to scale it, and how to make the right decisions while writing the application architecture.
Learn To Use Composables: The Swiss Army Knife Of Vue Developers
Vue.js Live 2024Vue.js Live 2024
163 min
Learn To Use Composables: The Swiss Army Knife Of Vue Developers
Workshop
Juan Andrés Núñez Charro
Juan Andrés Núñez Charro
Composables (composition functions) are stateful/stateless functions that can leverage Vue's reactivity API, decoupling it from components.This shift in perspective opens the possibility for tackling common scenarios in a new and creative way. In this workshop, you will learn how to solve typical problems every Vue developer faces, using composables:
- Data store;- Component cross-communication;- Utility functions (DOM, API, etc);And more.