Building Custom React Native Components From Scratch

   Community and Events

As we discover the rapidly growing world of React Native, we learn that it’s entirely possible to build an awesome application that leverages only the React Native code.  While the Facebook team has done a fantastic job of implementing a lot of UIKit out of the gate, it’s conceivable that there will be times when you need to go beyond the boundaries of what React Native out of the box (and soon to be Android Java).

Perhaps you want access to the recently released Apple ResearchKit, or you want to be able to leverage custom networking utilities like AFNetworking. What we’ve learned from our time with React Native is that the possibilities are endless for the developers wanting to take advantage of this capability.

From what we’ve gathered in our research, there are two types of custom components that you can implement for React Native applications; user interface and utilities. For this article, we’re going to focus on the utility type, as it has less moving parts and is a great way to get your feet wet with building custom component code.

Developing a custom React Native component

The application we’ll develop is rather simple.  It uses a custom React Native-enabled Objective-C class to write a random number to a file in your iOS application’s document directory and is a modified version of the custom PhoneGap plugin for iOS that I wrote in 2013.  This class writes data in a non-encrypted format, so please don’t use it in production.

In a nutshell, this demo application will take a filename as input from a React Native TextInput component. The user will be able to load data from the Phone’s filesystem based the file name.

Upon pressing Save, a random number string will be generated via a simple  Math.random().toString() method calls. The Load button performs the inverse, retrieving the contents of the file described in the TextInput and displaying it below.  We do all of this as well as some basic exception handling as demonstrated in the animated gif below.

Custom React Native Utility Demo

Instead of going through the rigmarole of the creating a React Native Project, we’ve decided to assemble an example and placed it in for you to easily checkout, execute and investigate for us to walk through together.

This github repo we created has two subdirectories, Phase1/ and Phase2/, both designed for you to review the implementation of each major phase of this article, as detailed above.

We’re going to kick this off with looking at the project structure itself.

A brief look at the project

Our example project is a generic React Native project with a small twist: instead of placing all of our React JS code at the root of the project, we place it inside of a folder known as jsx/.

The process for doing this is quite simple, as demonstrated below.

CustomComponent Folder

We perform this change for cleanliness of the project and suggest that anyone developing React Native applications consider something similar for it allows you to point your JSX editor to a directory that only contains the related JSX code, giving you the opportunity to visually locate files without having all of that XCode and Objective C mess cluttering your JSX editor’s UI.  Proactive organization will only benefit our app development efforts.

Because we changed project structure slightly, we had to inform React Native.  We do this by updating AppDelegate.m.  The process for doing this can be observed below.

updating AppDelegate.m

Before we can write any code, we’re going to need to inject our custom classes into the XCode project.  There are three great reasons to do this via XCode and not via some external editor.

  • When creating a Cocoa Touch class via this tool, the associated header file (.h), and program file (.m) are created with one process.
  • XCode will generate the class where we can define our class’s superclass, NSObject.
  • XCode will include our newly added class program to the list of files to be compiled (and linked).

Once the file is created, we will have to require the RCTBridge.h header file and leverage RCTBridgeModule as a protocol.

We will perform this action using XCode’s “New File” menu system as illustrated below.

XCode’s “New File” menu system

The Project is now structured as follows.

Folder Structure

Now that we’ve got the basic scaffolding stuff out the way, we can actually start writing code.  That’s why you’re here, right?

Phase one: Objective-C to JavaScript Bridge

The first thing we must do is fill in the MCFileWriterUtil.h header file.

The header file consists of a very simple class definition, without the method signatures to do the work required. This is because we’re going to leverage special macros to define and expose our methods to the React Native bridge.

With the header written, we can go on to write the meat of the Objective C class scaffolding.

As you can see, the contents of the write and read methods are nearly identical at this stage.  They are so because they are only setup for this learning phase.

There are three key takeaways from this phase of defining our custom Objective C class

  • The first key to look at is line #6, where the RCT_EXPORT_MODULE() macro is called. This macro is required to expose our custom module to the React Native bridge. We’ll see later on where we’ll require this module via JavaScript.
  • Next is the call to the RCT_EXPORT_METHOD() macro.  This macro is where the magic glue whose purpose is to expose our Objective C method signature to our future JavaScript code, hence the name “Objective C to JavaScript bridge”.  Technically, iOS doesn’t (as of iOS 8)  have an out of the box Objective C to JavaScript bridge (OS X does, though), so developers have been left to create their own bridge.  When comparing this to developing custom Phonegap iOS plugins (as detailed in this article), the Facebook team hit a home run with this implementation!
  • Last, the successCallback execution is something that we’ll also focus on. It’s worth noting that when calling the success or failure callbacks, you’ll need to pass an array of arguments to be executed on the JavaScript side.  Here, we’re just passing an array with one element, which happens to contain a string literal.  Again, this is just for demonstrating the bridging capabilities of the React Native Objective C to JavaScript bridge.

To implement this Objective C code we created, we’ll need to write some JavaScript code. We will add the block below to the project’s jsx/index.ios.js file.

The first item to focus on is the requiring of our module, MCFileWriterUtil from the React Native NativeModules module. We did not write a JavaScript class with that name.  The React Native Objective C to JavaScript bridge is what is responsible for making this available to our JavaScript code.

From there, we can execute the method MCFileWriterUtil.writeFile(), where we pass in four arguments: file name, file contents, error and success handlers, both of which  simply display a UIKit alert dialog with the string that is returned from the Objective C MCFileWriterUtil  writeFile method.

If you train your eyes to the Objective C code we have our write method for the MCFileWriterUtil class, you can see that there exactly four arguments, two strings and two functions.  When we execute a bridged method, we absolutely must call it using the defined arguments, or the bridge will throw an exception at you.

Ain't Nobody Got Time for That

From here, we can run the project and see that the bridge is doing its job and we can execute Objective C methods easily from JavaScript.

Alert - Success

OK, cool. We got this bridge running.  Our next job is to fill in the full contents of MCFileWriterUtil.m and write the code for the React JS implementation of our Objective C utility.

Phase two: Doing the real work

For Phase two, we are writing the actual Objective C code that does the actual work; writing and reading a file.

Here is the full implementation of MCFileWriterUtil.m.  It’s heavily commented, so I will not dive into the details of how things are working.

Before we move on to look at the JavaScript implementation, I would like to again point out that the React Native Objective-C to JavaScript bridge is absolutely brilliant.  If you look at the final if/else condition, you can see how easy it is to communicate with the JavaScript world.

For both conditions, we generate an NSDictionary literal (think JavaScript object, for you JS devs) to be used as an argument for the success and failure callbacks.  What you’ll see is that those dictionaries will automatically get transformed as JavaScript objects on the JavaScript side.

Speaking of which, let’s dive into the JavaScript implementation of our newly expanded Objective-C class. The code below is a long read, but I’ve commented it very well and the flow is easy to recognize.

There you have it! Developing Objective-C called by JavaScript has never been easier than with React Native.

Access this project in it’s entirety from our GitHub repo.

The future of developing plugins will change

It’s worth noting that one of the clear advantages of Facebook’s approach to releasing React Native is its Open Source licensing.  This has allowed near-biblical flood of community discussions, and a quite a lot of pull requests from enthusiasts who are willing to contribute their time and energies to better the project.

One such project is aptly known as “Pull Request #405”, where Joe Stanton has contributed a scaffold generating utility for custom React Native iOS code. We’re hoping that this pull request is merged soon and once it is, we’ll update our example (and this blog post) accordingly.

Resources to learn more

The Facebook React Native team has done a fantastic job with documentation for the framework. We’re thankful that they’ve taken the time to document the patterns for developing custom React Native components, which can be found here.  We highly suggest reading through it as it covers all of the patterns for developing custom React Native components for iOS.

In closing here’s a list of places people are discussing React Native:

This website uses cookies

These cookies are used to collect information about how you interact with our website and allow us to remember you. We use this information in order to improve and customize your browsing experience, and for analytics and metrics about our visitors both on this website and other media. To find out more about the cookies we use, see our Privacy Policy.

Please consent to the use of cookies before continuing to browse our site.

Like What You See?

Got any questions?