The Truth about React Composition To Fix Your Tremendously Convoluted Applications

Luke Brandon Farrell
4 min readJan 27, 2020

In this article, you will be introduced to component composition in React and React Native. After being involved in a number of large projects, and refactoring an unfair amount of frontend monoliths… We will examine the process behind building features which require multiple levels of components.

You are about to learn the very, very simple ways of component composition.

Let’s build a complex real-world scenario for a feature, and then go through how we would implement it, and which components we would need.

Components should be split between; concerned with style, and concerned with various levels of business logic, we will get more in depth with this below.

Scenario

We want to build a payment system, this system will allow users to view all their linked cards, we also want to add the ability for the user to click on a card and go to a page with their linked card, and its recent transactions.

Debit Card Component

For this example, we will explore the payment card component composition. Below is an image of the feature we want to build. There are two places this component needs to be used:

  • In the list of linked payment cards
  • At the top of the transactions screen
Example of where our payment cards are being used

Solution

First, let’s break down what components we need to implement, as an engineer should always plan what they are going to need, before writing the code.

  • PaymentMethod (this will be concerned only with style)
  • PaymentMethodItem (this will take a card object, and be concerned with business logic)

The PaymentMethod component will will only be concerned with style, animation and basic functionality e.g. an alert which asks you if you really want to delete. This will allow us to easily re-use the component in various scenarios. It also keep our code clean, and easy to understand.

Next the PaymentMethodItem, this will be used in the list of linked payment cards, and at the top of the transaction screen. It will take a card object from our API which will look like this:

{
type: "Visa",
ending: "4433"
expires: "12/02"
created_at: "2020-01-27T17:16:27+00:00"
status: "Active"
}
...<FlatList
data={cards}
renderItem={({ item }) => (
<PaymentMethodItem
card={item}
onPress={navigateToTransactions}
/>
)}
...

The reasoning for creating a specialised item called PaymentMethodItem, is because we need to process the card data, we need to feed that data intoPaymentMethod component, and maybe perform some processing e.g. convert expires into a date. The component would look something like this:

const PaymentMethodItem = ({ card, onPress }) => {
const type = card?.type;
const expires = new Date(card?.expires)
const ending = card?.ending;
const status = card?.status;
<PaymentMethod
type={type}
expires={expires}
ending={ending}
status={status}
style={{ paddingHorizontal: }}
onPress={onPress}}

As a bonus, we can switch some requirements and make things a little trickier to see how this system can handle it. We want to display the payment cards list in multiple places across the app (e.g. a snippet on the main dashboard, and in the settings). Both of these lists will navigate to the transaction view. How do we solve this, and avoid duplicate code?

First of all, it is not recommended to abstract the list as a component. The best approach is to move one layer up our component hierarchy, and extract a more specific payment card component, let’s name this PaymentMethodListItem.

We want to use the processing in PaymentMethodItem, so let’s wrap that in our new component, but now we handle the navigation inside PaymentMethodListItem, instead of our container screen. e.g. (in this example componentId is used for navigation)

const PaymentMethodListItem = ({ card, componentId }) => {
<PaymentMethodItem card={card} onPress={navigateToTransactions}
navigateToTransactions(){
Navigation.push(componentId, "TransactionsPage", { ... })
...

We just extract more business specific components, and wrap less business specific components of the same type.

There you have it! Clean composition. Please… please… please… apply this technique and thought process when building your applications, we don’t want more monoliths in the world.

--

--

Luke Brandon Farrell

Luke develops mobile applications using React Native. He writes about component-first architecture and design, code readability, and React Native.