React Native and Fable: Native Apps With F#

Datetime:2016-08-22 21:59:35          Topic: F#           Share

Skip down to the bottom for a choose-your-own TL;DR.

"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.

Developing With F# in VS Code

The app was developed with F# in  Visual Studio Code (with  ionide and  react native plugins). This development environment runs on all platforms, so you can use Windows, Linux or your Mac.

click to expand

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.

view 
  [ ViewProperties.Style [
      ViewStyle.JustifyContent Alignment.Center
      ViewStyle.AlignItems ItemAlignment.Center
      ViewStyle.Flex 1
      ViewStyle.FlexDirection FlexDirection.Row ]]
    [ button "Cancel" (fun () -> ()) //TODO: add cancel action
      button "OK" (fun () -> ()) //TODO: add Ok action 
    ]
  ]

This snippet creates a View component in React Native and puts two buttons inside it.

Using F#

One nice benefit of this model is that we can use ordinary, statically typed F# code for our app. In the demo project, you can find a small F# domain model:

type LocationCheckRequest = {
    LocationId : LocationId
    Name: string
    Address: string
} 

[<RequireQualifiedAccess>]
type LocationStatus =
| Ok
| Alarm of string

type LocationCheckResult = {
    LocationId : LocationId
    Status : LocationStatus
    Date : DateTime
    PictureUri : string option
}

If you are interested in learning the language then I recommend you look at the F# software foundation . For  domain driven design in F# , you can find excellent articles on a site called F# for fun and profit .

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 :

showImagePicker
    [AllowsEditing true] 
    (fun result ->    
        if not result.didCancel && 
           String.IsNullOrEmpty result.error 
        then
           x.setState { x.state with PictureUri = Some result.uri } )

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#:

async { 
    // getting data
    let! requests = DB.getAll<Model.LocationCheckRequest>()
    let! results = DB.getAll<Model.LocationCheckResult>() 
    // ....

    let newRequests = 
        [| { LocationId = "X1"
             Name = "Bell tower"
             Address = "Market place" } 
           { LocationId = "X2"
             Name = "Graveyard"
             Address = "Right next to church" } |]

    do! DB.addMultiple<Model.LocationCheckRequest> newRequests

    // ...
}

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:

async { 
    let url = "https://www.myserver.com/api/LocationCheckRequests.json"
    // Fetch demo data 
    let! requests = fetchAs<LocationCheckRequest[]>(RequestInfo.Url url)
    // ....
}

So we see the same async model here and everything fits nicely together.

Project Status

The project with the working title “Fable |> React Native” is currently considered “highly experimental.” APIs and JavaScript bindings are not complete and likely to break multiple times.

In general, the Fable project is shaping things up for a v1.0 release. So sharing experiences, comments, and bug reports with the Fable compiler and APIs is appreciated.

Debugging of the react native apps is currently only working in the generated JavaScript. With the next release of the  VS Code React native extension we will  probably be able to set breakpoints directly in the F# source .

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.

TL;DR for C# Devs

Sorry, nothing to see here.





About List