The New LEGO — Wield the Enormous Power of Reusable Components in React

The React Native Rewind
8 min readJun 7, 2019

--

When I was five years old my dad would stop at the petrol station once a week and buy me a small box of LEGO, twenty years ago petrol stations used to sell miniature LEGO models. I was overwhelmed with joy to get some new LEGO pieces once per week, to bring them home and add them to my box of LEGO.

Photo by Rick Mason on Unsplash

The spirit of building with LEGO has always lived on in me, but now as an adult, I use more sophisticated tools; instead of plastic blocks and plastic boxes, I use React and Node Package Manager.

Frameworks (e.g. React, Vue) that have allowed us to create components have given developers the ability to write code and reuse it like LEGO. The ability to use your code across your application, across many projects, and even share it with the world via open-source for others to critique, improve and use.

Tools like Github, Bit and NPM have allowed developers to build components which work in isolation and can be included in any project, just like a piece of LEGO. Projects can include components in three simple steps:

  1. Install the package to your project — …you get your new LEGO box with all of its pieces from the petrol station… “NPM”.

2. Import the components from the package — …pick out the best pieces from your new LEGO box.

3. Use the component in your project — …resume building your LEGO masterpiece with your new blocks.

Components are the new lego…

Building lego sounds fun, but it’s not that simple.

We learn as developers that you should make your components as small as possible, with a single responsibility, this is a great ideal, but in complex applications things can get messy. Components become complex because inherently they bring with them a responsibility to the project or ecosystem:

  • Some components can only be used across the project
  • Some components can be used across many projects, but are too specific to be open-sourced
  • Some components can work in isolation, and can be open-sourced
  • Components need to be styled to fit the project(s).

The aim of this article is to explore how components can be categorised, designed and distributed for maximum reusability.

Sharing Components

Firstly let’s talk about how components can be shared across your project(s), then you can understand how to categorise your components by the ways they are distributed.

Isolated Component

An isolated component can be extracted out of the project and installed using a package manager of your choice… “NPM”, this component can work in isolation, the only crucial dependancy is the framework for which it belongs, e.g. if it is a Vue component, it should work in any Vue project when installed.

It does not matter which patterns the component is built with, the only important thing is that it can be included in your application. You add them to your project like LEGO, and they live in the “box of LEGO” (the NPM repository) out of sight and ready to be used.

An example of an isolated component would be my react-native-images-collage library, like a brick of LEGO, the component will slot into any react-native project.

Organisation Component

There is a subset of components which are too specific to the organisation to be fully extracted and open-sourced as an isolated component. Organisational components can be open-sourced internally, and used across multiple projects in your organisation.

There is no need to start new software from scratch, with your companies branded LEGO bricks you have all the building blocks to get started.

What is the best tool to share components across your organisation? Bit is new to the “block”, and is a great tool for sharing components across your organisation.

Component Library on Bit

In some cases, an organisational component will show potential to be used in projects beyond the organisation, in those cases, you may consider distributing it as an isolated component.

Project Component

Project components are similar to organisational components, although they are specific to a single project, your components don’t need to be extracted to NPM or Bit, they can be built and consumed directly from your project. The common practise is to keep project components in a folder called /components.

If a project component starts to be required in other projects, then it should be promoted up the hierarchy to an organisational component.

Specialised Component

Let’s admit it, sometimes your files can get big, and your pages can end up with lots of repetitive code. It is necessary to extract patterns from your pages, but what if the extracted patterns are very specific and only apply to a single page, or a single part of the application? Then we build a specialised component.

The best practise for this type of component is to embedded it in the same file as the page it is used on, or in a separate file, but in the same folder. e.g.

/landing-page
LandingPage.js
LandingItem.js <-- This is a specialised component
LandingResponsiveImage.js <-- This is a specialised component
// Like normal, you can build your components as you see fit. e.g. /landing-responsive-image
index.js
test.js
style.js

The example below showcases the profile screen for the React Native application I have contributed in building; “Reward Me Now” at Redu, we use a specialised component for rows on the profile screen.

const ProfileScreen = () => (  ...  <ProfileRowItem
onPress={() =>
Navigation.showModal(component("EditProfileScreen"))
}
icon="edit"
name="Edit Profile"
/>
...
)
const ProfileRowItem = ({ icon, name, onPress }) => {
return (...);
};

As with the other component types, if the ProfileRowItem component is needed in other parts of the application, we can promote it up the hierarchy to a project component.

Building Components

The way components are shared influences how they should be built. Just like LEGO bricks we need to split our components into small pieces, so let’s get building!

Functional Component

A functional component has a single responsibly of providing functionality. Below is an example of a button component which includes a spinner if isLoading is true.

import { Button, ActivityIndicator} from "react-native";const BaseButton = ({ text, isLoading, ...props }) => {   if(isLoading){
<Button {...props}>
<ActivityIndicator />
</Button>
}
return (
<Button {...props}>
{text}
</Button>
);
};

You may be asking, where do you define the style for the BaseButton component? The answer is you don’t… if you want to style your custom button component you wrap it in another component such as <SecondaryButton /> or <StyledButton variant="secondary" /> . This allows the<BaseButton />component to be used across your organisation, as functionality and styling can require a different scope. e.g. you may want the button functionality in one of your projects but with a completely different style.

A good pattern to follow is to name all your functional components with a prefix of Base e.g. BaseButton, BaseTextInput, BaseCheckbox.

Styled Component

These components are concerned with.. you guessed it! style. There is no need to use styled-components, “Styled Components” is just the name I have given to this subset of components. As mentioned above, a styled component is used to wrap another component and give it; page specific (specialised), project specific or organisational specific style.

import { Button, ActivityIndicator } from "react-native";const StyledButton = ({ variant, ...props }) => {   if(variant === "primary"){
<Button style={...} {...props}>
<ActivityIndicator />
</Button>
} else if() {
<Button style={...} loadingStyle={...} {...props}>
<ActivityIndicator />
</Button>
}
};
const styles = ... // or an external style sheet

In the example above the styled button will have the isLoading functionality. You may want to define a PropType for isLoading on the StyledButton so other team members can see the available props in their IDE.

Functionality and style can sometimes require a different scope. The style may be specific to your project or specialised, while the functionality can be used across the organisation.

Composite Component

A composite component is made up of other components, either homegrown or third-party. The purpose of this component is to pull components together to build reusable patterns.

An example of a composite component may be concerned with an extension to a<TextInput /> component.

import { TextInput } from "material-text-input"
import { MDPassInput } from "material-password-input";
const TextInputWithPassword = ({ password, ...props }) => {
if(password){
return <MDPassInput colour="#F91276" { ...props } />;
} else {
return <TextInput colour="#F91276" ( ...props } />;
}
})

Composite components are built to share complicated patterns. A composite component can follow the constrains introduced above in the functional and styled components section, e.g. a form which parses and sends an email which is shared across the organisation:

import { View } from "react-native";
import { BaseButton } from "../components/base-button";
import { BaseTextInput } from "../components/base-text-input";
const EmailForm = ({ TextInput, Button, style }) => {
<View style={style}>
<TextInput name="email" ... />
<Button onPress={parseEmailAndSendToAPI} ... />
</View>
function parseEmailAndSendToAPI(){
...
}
};

The above component is composite because it brings multiple components together to form a complex pattern, it is also functional because it is not concerned with style. To style this component you pass your project / specialised styled components into the EmailForm props.

<EmailForm TextInput={StyledTextInput} Button={StyledButton} />

Composite components can be specialised, used across the project, within the organisation, or open-sourced.

Conclusion

The key to building great components lies within the scope. Following this model and moving your components up the hierarchy; specialised -> project -> organisation -> isolated… as they are needed in other parts of your project, organisation, and community will help you build more robust L̶E̶G̶O̶ ̶b̶r̶i̶c̶k̶s̶ components.

Photo by James Pond on Unsplash

BONUS: Styling Components

The advantages and disadvantages on the various methods of styling components are discussed throughout the internet every day. Here are some of the ways you can style components:

  • Inline styling
  • CSS Stylesheet
  • CSS Modules
  • styled-components

But a question we should ask before choosing one of the methods above, is how is the component distributed? Is it specialised, project specific, organisation specific, or isolated.

The scope of your components dictate how they should be styled.

A specialised component may use inline styles or styled components, a project specific component may use CSS Modules, an organisational component may include a CSS Stylesheet or context consumer, while isolated components will come with props to extend the style.

Below is an example of an <Alert /> component and the method of styling depending on the scope of the component.

At a specialised level where the component is only built for a single page:

Alert for usage inside a single file (specialised)

Using React you can allow your project and organisational components to be extended further using the context API. You can use a theme value which can be consumed by your components. At a project / organisation level the component may look like this:

Alert component for project / organisation

At an isolated level where the component is built for open-source and distributed via NPM:

Alert component for open-source

Hope this improves your LEGO building!

--

--

The React Native Rewind
The React Native Rewind

Written by The React Native Rewind

What's new, what's coming, and what's worth your attention in React Native - along with humour, occasional rants, and memes.

No responses yet