(Updated 13/04/2017: Bumped to React Native 0.42.3 and updated code)
One of the cool things I like from working at Badoo, is that we are free to propose, test and promote new or different techniques, technologies and libraries. React Native has been the buzzword for a while now, but it has recently caught our attention.
The main concerns that occurred to us were the size of the existing codebase (let’s say, sizeable), our highly customised classes to fit our needs and easiness of integration. I decided to test the middle one, and try to write a custom Android component to use in React Native.
You can learn all about it in the project page.
If you generate a demo project by invoking react-native init, you will get a working skeleton, which is what I will base this post on.
Let’s attempt to extend it by adding a simple ProgressBar. This is already implemented as part of the standard React Native distribution, but will serve us as an easy sample.
Extensions to the existing bindings are made by implementing the ReactPackage class. It can be done in three different ways:
- ViewManagers Native views are provided through implementations of the ViewManager class, responsible for instantiating and updating views of a given type. This is the one we are interested in for now.
Since we are only setting up a native view component, we will need to go from the ViewManager all the way up through several layers.
All ViewManager instances need to report two things: a name to be mapped to a React class, and a way to create an instance of the view they manage. For our ProgressBar example, this is quite easy.
Here, ThemedReactContext is just a wrapper on top of the Android Context we all know (and perhaps hate). With this done, React Native is able to instantiate a ProgressBar each time it finds the JSX tag for it.
At the package level, we do not need to return anything but our brand new ViewManager.
The rest of methods can return empty collections safely for now, since we do not need anything from them.
The entrypoints: ReactNativeHost
This step is quite simple, since most of it is handled by the React and React Native code. The only thing left for us to do is to describe the propTypes and export the module.
You might be wondering what those default view properties are. Since we inherited SimpleViewManager (which extends BaseViewManager) when creating our own ViewManager, we can take advantage of that to have all the basic mappings from CSS to View properties solved for us. These include properties such as opacity, backgroundColor and flex. A full list is available here.
What if we want to expose our own? Well…
Exposing view properties
On the Java side, we need to create our setters in the ViewManager implementation and annotate them with @ReactProp. There we note the name of the property coming from JSX world, and optionally we can define a default value.
This setter will be called every time the property of our React component is updated. In case of the property being removed, then the default value is used. Then, we need to add it to the React Native interface. Back in the js file, at our module’s iface we should describe the properties we exposed in the ViewManager, both with name and type.
This way, both Native and React sides will speak in the same terms. In the end, our module’s JS file would look something like this:
Kickstart the react-native server, deploy the APK to your favourite emulator or real device, and if nothing is missing the million-gear machine will produce something that looks more or less like this.
React Native, more than a year after its public release (and not even one year after the Android release), is in a way more mature state than the last time I attempted anything on it. You can have a working boilerplate project with one command. Docs are very helpful and community content is great.
However, it still feels very cumbersome to integrate it with complex modules.
There is, nevertheless, an alternative approach. Instead of having a brand new React Native application adopt Native components, there is the possibility of doing the complete opposite - having a mature production application integrate one simple React Native component.
From reading the docs, it looks more complicated than it sounds, and I have some concerns about the build process - speed and reliability. But that’s food for another thought, and most likely another post. Stay tuned!
This article was originally published on Guillermo’s blog.
Guillermo Orellana - Android Developer