React Native and Fable: Native Apps With F#

"A React Native App Is a Real Mobile App"

With React Native, you don’t build a “mobile web app”, an “HTML5 app”, or a “hybrid app”. You build a real mobile app that’s indistinguishable from an app built using Objective-C or Java. React Native uses the same fundamental UI building blocks as regular iOS and Android apps. You just put those building blocks together using JavaScript and React. [ project site ]

That doesn’t sound too bad, but why do we have to do it in JavaScript?

Well, this article shows that we don’t have to.

The Nightwatch App

Consider you are working for some kind of night watch; it’s getting dark and your watch is about to begin.

The nice people of your order gave you a phone and a new app. At the beginning of the night, it downloads a list with locations that you have to check. Every location can be marked as OK, or you can blow a virtual horn to trigger an alarm. The app also allows you to append a photo of the situation on the ground.

Since many of the locations that you will visit are far away from good internet connection, the app stores everything locally on your phone. Once in a while, it will sync with the nightwatch central.

So this could look a bit like this:

So now after embarrassing myself and showing my design skills, let’s jump into the technical stuff.

As you can see, we have a React Native app with automatic loading of compiled F# code.

The big difference to using JavaScript is that everything is statically typed—even the access to the JavaScript APIs. This gives you nice autocomplete features and, depending on the concrete bindings, you can even get documentation in the editor:

click to expand

Krzysztof Cieślak did really amazing work with Ionide —this tooling works pretty well. Take a look at his blog to find out more about the awesomeness that he brings to the ecosystem. He also played an important part in getting React Native to work with F#.

Introducing Fable

Fable is the most important technology behind all of this. It was designed by Alfonso Garcia-Caro as a F#-to-JavaScript compiler and can do real magic in the browser. Take the time and watch the 10min intro . I can’t stress enough how well this open source project is managed. It’s a real pleasure to be part of it now.

In our case, it bridges React Native APIs into F# and also compiles the F# code back to JavaScript whenever we save a file. The React Native framework is listening for the changes in the JavaScript files and swaps the code in the device simulator. There is a lot going on behind the scenes, but it’s already working surprisingly well.

Using JavaScript APIs

Since most of the React Native APIs are developed in JavaScript, it’s important to bring these APIs over to F#. This is done as a community effort and the Fable project creates typed JavaScript bindings for many major JavaScript frameworks. This effort is comparable to DefinitelyTyped in the TypeScript world. There is even a tool that can help to convert TypeScript bindings to Fable bindings.

In our case the fable-import-react-native is the most important package. It provides typed bindings to most of the React Native APIs.

Access to Native Components

React Native allows you to access native phone components like the camera. Most of these APIs are written in a mix of Java/ObjectiveC and JavaScript. Given the Fable bindings are already present it’s super easy to access the same APIs from F#. In the following sample we access a nice ImagePicker via the fable-import-react-native-image-picker bindings :

This ImagePicker is distributed via a separate npm package, but its API feels like the rest of the React Native functions. We can provide some properties and a callback—and everything is statically typed so that we have autocompletion in VS Code.

Data Storage

For most apps, you want to have some local storage in order to cache information. React Native provides a basic abstraction called AsyncStorage that works on Android and iOS. With the help of a package called fable-react-native-simple-store we can use it from F#:

As you can see, all functions in this storage model are asynchronous and, with the help of the async computation expressions , they become really easy to use in F#.

Web access

Another advantage of React Native is the huge ecosystem you see on npm . In our app, we want to retrieve a list with locations that we need to check. This list is just a bit of JSON on a HTTP resource. With the help of a very popular JavaScript package called fetch and the corresponding fetch-bindings (written by Dave Thomas ) we can write something like this:

That said, it already feels very very productive and if you are interested in this kind of mobile development then check out the sample project and follow how it develops over time. There is even a similar approach that allows you to use F# on fuse , so I think we will probably see a lot of choice in the future.

TL;DR for F# Devs

With this model, you can start to develop Android and iOS apps on the React Native model while still keeping most of the type safety and tooling. Using Fable gives you access to a huge ecosystem with JavaScript libraries and frameworks. Check out the sample project and follow the instructions in the Readme.

TL;DR for JavaScript Devs

If you like creating apps with the React Native model, but it always felt a bit difficult to maintain JavaScript, then this might be interesting for you. With this approach, you can apply all of your knowledge and use it from an excellent typesafe language with amazing autocompleting tooling.

With one or two tricks you can even reuse many of the npm libraries that you know and love. Check out the sample project and follow the instructions in the Readme.

TL;DR for TypeScript Devs

You have already left the path of plain JavaScript. Maybe you are ready to stray a bit further and begin to investigate different languages like Elm or PureScript . If this is you then check out the sample project and follow the instructions in the Readme. It shows you how a language like F# can help you to work with JavaScript APIs.