Writing a React Native App in PureScript?

Hi :slight_smile:

I saw that @mouton wrote that he is using PureScript for a react-native app…

I also want to write a React Native App in PureScript. Does that mean I can’t use Halogen (I have to use React)? (I’ve been using Halogen for a web app at my job and I really like it.)

Should I use this? https://github.com/doolse/purescript-reactnative
If I use that, could I later easily transition the native app into a (purescript react) web app?

Do I need to install Android Studio, or is it possible to avoid installing it (it uses a lot of disk space)?

What are the necessary tools I need to install, at the minimum?
(If I want to run the app on my real Android phone via adb, instead of installing the Android Studio emulator.)

(I’m using Arch linux btw, but I also have a laptop with Win 8.1.)

Btw, do you know if WebBluetooth can be used from a react-native app?
(I have to communicate with a receipt printer via Bluetooth.)

Thanks! :slight_smile:

Hi Boscop
Sorry to send you away, but if you read again, I only wrote some core logic in purescript, not any of the react or native part.

A

I’m writing a fairly significant React/React Native app right now (hope to have something releasable by the end of summer). I posted a gist not too long ago showing how to get RN up and running in under 5 minutes: https://gist.github.com/dwhitney/e2a040432040607ae519fdf05cbc27ad

First, Halogen definitely won’t work with RN because of its purescript-dom dependency. If you even so much as whisper “DOM” or “window” in the vicinity of a RN app, it will immediately crash with an obscure error leaving you hopeless and helpless. This is true even if you think that stuff is safely buried in a function that definitely won’t get called.

From there, I think the people who’ve created purescript-react and purescript-reactnative have done a good job, but they both fall victim to the common issue most wrapper libraries have: they fall woefully out of date. I say this now after both have just been updated, so take my criticism with a grail of salt - but when I started my app, both libraries were on different versions of react and upgrading purescript-reactnative to the same version of purescript-react caused purescript-reactnative to immediately crash because the lib referenced a component that had been removed from react native (a navigation thing IIRC). I forked and fixed this and made a PR but saw that someone had done the same several months earlier and it hadn’t been merged. C’est la vie. I’m far worse about this stuff that the authors of these libraries are, so I hope this isn’t taken as harsh criticism, but simply a fact one must adapt to when joining a relatively new language.

In light of all of this I decided to “roll my own”. This is simpler than it sounds. If you look through the source of purescript-reactnative you see that most of the library is unlocked by these 40 lines of code (most of which I don’t need) https://github.com/doolse/purescript-reactnative/blob/master/src/ReactNative/Unsafe/Components.js – I figured I could just do that too, which is essentially what my gist up top does. Next I noticed that purescript-react-basic unlocks React with about 60 lines of code: https://github.com/lumihq/purescript-react-basic/blob/master/src/React/Basic.js – figured I could do that too, so I did, and you can see the most essential elements of both working in the gist.

Beyond that, I wanted to make sure that I kept up to date with the latest version of React and React Native, so I took my dev environment a step beyond what is typical and added babel and flow. I added a separate directory for JavaScript code where I write ES6 with Flow types that are compiled into the PureScript src directories. This makes upgrading a breeze since I get Flow checks against the JavaScript libraries whenever I want.

To make my code work in both web and RN, I wrote a little Component DSL and CSS DSL that works with purescript-run and accompanying interpreters that write either React or React Native. Though I didn’t plan this, I recently got the added benefit of trivial server side rendering since that was simply another interpreter. It has worked out well (much thanks to Nate Faubion for the fantastic libs!).

I have liked this approach so much that I’m pretty much on the mindset now that wrapper libraries should be avoided and you ought to bite the bullet and write a touch of FFI when needed (under 200 lines in our case, which represents 0.01% of the codebase).

HTH

6 Likes

Also as for needing Android Studio - create-react-native-app comes with Expo, which makes getting all of this up and running a billion times easier. You can immediately start testing on your phone with the Expo app, and I literally did nothing to get an emulator running on my mac. I do think you’ll have to go through the hell of setting up Android Studio to get an emulator running on linux, but in the meantime you can easily test/explore on your phone (hot reloading works too!)

2 Likes

Thanks for the detailed reply.

I haven’t used react before so I’m not that familiar with it (only Polymer, and then switched to Halogen), and I’m not an expert in PureScript yet (especially when it comes to writing FFI code correctly, where it’s not type-checked)… (Btw, I came to PureScript from Rust, not Haskell…)
So I would prefer to use existing react-native PureScript bindings…

Would it be possible that I could use your react-native bindings? Did you make them available publicly? :slight_smile:

Halogen mentions this regarding the h parameter:

h is the type of value that will be rendered by the component. This is always HH.HTML when a component render function uses ComponentHTML. The parameter exists to give us the possibility of non-HTML components for things like React Native.

I asked @garyb about this a while ago on Twitter who explained what would be involved in adding a React Native driver. I didn’t see it through very far at the time but have thought about revisiting it now that I have more experience with Halogen.

I came to PureScript from Scala and had experience working with Free monads which is essentially what purescript-run is. Free monads are simple once you grok them but a complete mind fuck up until then. And I don’t think my DSL would be all that useful to anyone who didn’t buy into the philosophy behind what I’m trying to do which is build a library that works across web and native. It basically starts from the fact that you can build an entire website out of just div tags and styles and tacks things on from there as needed - it’s more robust than that in that I want semantic tags but you get the idea. All this said I think you can get some decent mileage out of purescript-reactnative

Yeah I really like purescript-spork and wanted to do the same. There is a lot involved. The first non-obvious thing is absolutely nothing expecting the DOM or typical browser things like window or document can exist. This goes for JavaScript as well as PureScript. I thought if I didn’t invoke any functions that called these things I’d be fine. Nope. Just including them causes RN to crash immediately. If you can figure this out I’d love to know how.

In light of this I think you’d have to fork halogen and make halogen-dom with all of the DOM stuff segmented off. After that you would build your driver but this is a little odd too. RN supports just a subset of CSS and if you include CSS properties that are unsupported or with the wrong type your app will fill up with warnings. This is mostly ok but a little annoying. My CSS DSL only allows the properties that RN supports, and all of the components are type checked against these properties. Also the properties must be camel cased. I’d imagine this would be time consuming with Halogen. Next, the basic components in RN is called View. It doesn’t have the ability to scroll. So to overcome this I made it so all of my components when rendered to web have “overflow”:“hidden” by default and then I inspect the CSS for “overflow”:“scroll” and in RN I render a ScrollView. I think if you keep these things in mind you could make it work.

@dtwhitney have you seen react-primitives and react-native-web?

Yeah I considered using them but decided against it. I thought it would actually result in more work and I’d be writing a wrapper for a wrapper… In the end making this all work isn’t much code. But I do take the approach primitives has and have a very small subset of base components was with fairly strict boundries where React Native is the limiting component

If I use that, could I also build the same app as native (for Android and iOS) and web app?

purescript-reactnative has purescript-react as a dependency which means all of the elements to make this work are available to you once you’ve added purescript-reactnative as a dependency. That said, there is a lot of stuff to know starting with react and react native. At a high level they are the same, but there are a low level details to work through. I wish it were simpler

I have liked this approach so much that I’m pretty much on the mindset now that wrapper libraries should be avoided and you ought to bite the bullet and write a touch of FFI when needed (under 200 lines in our case, which represents 0.01% of the codebase).

sounds like a blog post idea!

that would necessitate a blog :slight_smile: