Writing multi-platform mobile apps with React Native and KotlinJS
Kotlin is an awesome language. It is functional and offers extension functions, null safety, smart casting, type-safe builders, default and named arguments, data classes and much more. It is arguably the language of choice for Android developers and very familiar to iOS developers.
React Native enables us to write only once for multiple platforms, has a simpler API than native development and a smooth learning curve. Steve Yegg, a former Google engineer, conjectures in his blog post that hybrid frameworks are likely to become even more popular. And the framework from Facebook is the major player at the moment.
So why not mixing both?
Standing on the shoulder of giants (JetBrains/kotlin-wrappers and ScottPierce/kotlin-react-native), we can.
An example repository can be found here.
React in a nutshell
You can learn the basics of React Native very quickly reading the official tutorial, but three important takeaways are:
- view = f(state)
- React has a virtual representation of the view, and it calculates the smallest diff between renders
- development should be component-driven
Hello world in Kotlin
After cloning the example repository and following the README, you can simply edit the render() function to immediately see the result on the device.
For example, writing the following code…
…would render the following output:
Thanks to the Kotlin language features, we can write the view using a builder DSL similar to JSX, instead of manually calling React.createElement(…, React.createElement(…)).
Creating our first component
Let’s say you have the following view architecture and you want to make the code for headers reusable:
For this task, you could create a Header component:
And call it from the render() function as such:
Alternatively, if you want the extend the DSL so that you can call this component directly, just create an extension function:
Managing state
React doesn’t dictate how state management should be. For the sake of this example, let’s write our own simplified, naive implementation of Redux.
In this pattern, we have three main elements:
- store: holds the state
- actions: describe the changes
- reducers: return an updated state based on the requested action
Here is the full implementation:
Evidently, on a real world application, you should prevent race conditions and implement the subscriptions in an atomic fashion, possibly using RxJS. But that’s good for now.
A less contrived example
Now let’s write a simple application which consists of a header, and two rating widgets, for giving scores to two different programming languages.
First we create the models:
Then the actions that can be dispatched:
Later on, we define the reducer:
Then we define a view model, mapping state to view abstractions:
We connect everything with a store:
Finally, we create a stateless, dumb component:
And another component that keeps track of the state:
And the final result is:
So… Is Kotlin with React Native production-ready?
Possibly, but there are still some improvements to be made to the whole ecosystem. The interoperability with JavaScript isn’t effortless and has some pitfalls. For example, passing the store via props to the component won’t work because the state will become immutable. Also, using data classes for the props directly will return an error from React because apparently the serialization contains some metadata. In addition, you’re supposed to write your own type definitions, which is a huge productivity killer.
I think JetBrains is to blame for the unpopularity of KotlinJS, by not giving the language the love it deserves. Kotlin/ts2kt, for instance, could solve the type definition problem. However, most of the attempts for converting types fail, and the issues remain open. Actually, we don’t see many examples targeting JS at all, despite the fact that this a working platform for more than a year. Maybe they are focused on Kotlin/Native…
In the meantime, another alternative to JavaScript is Clojurescript, which is awesome with re-frame and in my opinion offers the best development experience out there. However, it’s not for the faint-hearted.
I hope that with this article and the example repository, the community can reconsider Kotlin as a language for React Native. Feel free to fork the code!