How I Built My First React Native Library

14 May 2021
This article was originally published on Medium

Published On:

14 May 2021

Tags:

react native
javascript
npm

In a previous article, I described the process of building Flipping Cards, a language learning app that was also my very first mobile app development project.

One of the long-awaited features of this app was Challenge Mode, where the user can test his knowledge in a quiz-like interface: given the English word, the user has to type it in German, articles included.

While sketching the UI for this mode, I realized that a simple input text was not going to be very user-friendly: first of all, in the case of a noun, you are supposed to type the article and then a space between the article and the word. This, to me, looked a little bit cheap. Moreover, I wanted to give a visual hint on how many letters the word has. This led me to consider this type of input:

hello world

So I started researching a React Native library that allowed me to do this. The first challenge was to find out how this thing is actually called. Some of my search keys were:

  • individual character input

  • single character input

  • multi box input

  • single letter input

Turned out that there’s really not much out there. This type of interface seems to be very common in OTP (one-time password) screens, but this usually means that only numbers are supported, or that there is no support for spaces, line breaks, and so on. Moreover, most of the projects that I found were written for React but not for React Native. At the end of my search, I was left with no eligible libraries for my goal.

Therefore I ended up with the typical answer:

“Fine, I’ll just build it myself “

Step 1 — Building it as a component in my project

In the beginning, I was mostly focused on having this functionality for my project, therefore I just created it as a component in the Flipping Cards project. The core idea was to accept a word structure (which is an array of booleans where true means letter and false means space) and then render individual one-letter text inputs for each letter or a spacer when needed. While typing, a callback function is executed and the typed word (as an array of letters and as a string) is passed as a function argument.

Without boring you with all the details, there were many unforeseen challenges that I had to tackle:

Managing the backspace behavior was not that trivial: the core idea is that when hitting backspace, the focus goes to the previous input, and the letter gets deleted. But what if your focus is on a box with already a letter in it? In that case, you want to delete the current letter only if the cursor is after the letter.

backspace
Different cases for the backspace behavior

Another challenge is that I wanted to efficiently split the word into multiple lines when needed. For doing this I created a setting called maxBoxesPerLine and then I implemented a logic which creates letter chunks based on this setting.

extraterrestrial
A long word with maxBoxesPerLine set to 12

I also created a setting called lineBreakOnSpace, which always creates a new row for a new word.

linebreak on space

At the end of this process, I integrated this new component into my app, tested it, and then shipped the long-awaited Challenge Mode feature.

Step 2 — Releasing it as a standalone library

After the feature was shipped I re-looked at my component and noticed that it was isolated enough to be quite easily shippable as a standalone library.

This was my very first attempt at this type of project, so I started looking for a template for the repository. The main goal was to have a project which allowed me to:

  • Run the component in the device emulators (iOS and Android)

  • Work faster on the updates with Hot Reloading

  • Write code in TypeScript

  • Write tests

  • Easily export the library as npm package

After some research, I’ve found this excellent template, which matched all of my requirements. The project comes with a /example folder which contains the demo app. This is already configured in a way that will let us import our component as if it was an existing dependency in the project.

import { ComponentName } from 'react-native-library-name';

The example project can be launched in the device emulators and the component can be edited in real-time, just as if you would do when working on a standard React Native project.

Testing

Since the logic for splitting the words into rows when needed (based on the settings mentioned above) is quite tricky, I realized that this was a good use-case for some unit tests. The template already comes with Jest installed, so I created tests for covering different scenarios. Another thing that I included in the tests is the method that returns the index of the input box where the focus is supposed to be shifted (for example when hitting backspace or typing a letter).

unit tests

These tests are even executed every time I push my commits, via GitHub Actions, therefore I immediately notice if I break something when updating the component.

github actions

What was still missing is a way to visually test the component with the possible combinations of props. For this, what turned out to be a great tool is Storybook for React Native. I was already familiar with Storybook as a powerful utility for testing UI components for web projects in an isolated mode. However, I was not aware of the React Native support. The great thing is that it allows interacting with the components in 2 different ways:

  • directly from the device emulator

  • from the Storybook server (accessible via browser)

After setting up Storybook in the project, I created these stories:

  • default case: the component in the most basic version, with only the required props

  • a playground case: here I allow to customize all the possible props (including background color, input size, and so on) thanks to the knobs feature

  • common use cases: a set of standard combination of props for the most typical configurations of the component

When everything was ready and properly tested, there was only one thing missing: the name.

After running a poll with some friends/fellow developers I ended up with the name: react-native-quiz-input

The library is now available on:

I also wanted to have a playground that was easily accessible for developers wanting to try out the component before downloading it. Therefore I created a Snack on Expo.io which allows you to try out the library on a real device or even in the browser, thanks to React Native Web support.

Antonio Cosentino © 2021 - All rights reserved