Spelunking series: React Native

codecraft

In which I try to avoid Hell as much as I can

I've heard a LOT of things, good and bad, about React Native (or RN for short) so I have decided to do a bit of prodding. I'm going to start with this tutorial and hopefully it will take me to a place I didn't know I wanted to be in.

2016-03-22 17:47

Around four hours in and I'm still not done setting things up. I don't really have a clue why it's taking me so long (or why the errors are so arcane to me), but it's understandable given that the RN project is just over a year old (This is actually one of the reasons why I'm so interested in it: it's still possible to make a mark.)

2016-03-22 17:56

Fig. 1: My first successful React Native app is a blank canvas (which means, it's full of possibilities, eh?)

I ran:

react-native run-android

...and it worked! Let's see what we can do here.

2016-03-22 18:13

Fig. 2: Spoke too soon.

That was kind of embarrassing. I really thought everything was going well until this popped up. But then it turns out if you shake the screen, you get this:

*Fig. 3: Progress at last. *

I googled for answers and put [insert my ip address here]:8081 (which is the default port of the server RN uses) under Dev Settings -> Debug server host & port for device and hoped for the best. But it turns out that this wasn't the problem at all. You see, I have just committed what seems to be a very common rookie mistake in using RN: I didn't start the goddamn Node.js server! So I ran:

npm start

And reran the whole thing to get this:

*Fig. 4: Sweet, sweet hello world. And yes, I know the times are wrong. I took Fig. 3 after I got it working. *

I'm going to take a break. I sure as hell deserve it.

2016-03-22 23:20

As far as I can tell, this is how you get RN for Android to work on an Arch installation. This process will probably still be valid in the next few months.

Step 1: Setup the necessary things

# Install Android dependencies from the AUR (I use pacaur as my AUR helper)
pacaur -y android-sdk android-sdk-platform-tools android-sdk-build-tools android-platform

# Add the following to your ~/.bashrc
export ANDROID_HOME=/opt/android-sdk

# Make an sdkusers group so that you can build without root
# This is needed because /opt requires root access
groupadd sdkusers
gpasswd -a $USER sdkusers
chown -R :sdkusers /opt/android-sdk
chmod -R g+w /opt/android-sdk
newgrp sdkusers

# Install additional Android dependencies
# Make sure to install the ff. packages:
# * Android SDK Tools (latest)
# * Android SDK Platform-tools (latest)
# * Android SDK Build-tools, revision 23.0.1
# * SDK Platform Android 6.0
# * Intel x86 Atom_64 System Image, Android API 23
# * Intel x86 Atom System Image, Android API 23
# * Local Maven repository for Support Libraries (latest)
android list sdk -a
android update sdk -a -u -t 

# Install JDK, gradle, and watchman
pacman -S jdk7-openjdk gradle
pacaur -y watchman

# Enable the gradle daemon
touch ~/.gradle/gradle.properties
echo "org.gradle.daemon=true" >> ~/.gradle/gradle.properties

# Install node.js
pacman -S npm

# Install react
npm install -g react-native-cli

Step 2: Make react run on your Android device

# Make a project directory 
react-native init SampleProject 

# Start the node.js server inside project directory 
cd SampleProject 
npm start

# Check if device is recognised by OS 
# You should see "device" beside your device's serial number 
# If not, make sure USB debugging is enabled and 
# run the command "adb version"; something will 
# pop up on your device. Pick OK or whatever is 
# the most sensible option. 
# Note that only one device should be connected at a time 
adb devices

# Expose Node.js server to device # AFAIK Node uses port 8081 by default 
adb reverse tcp:<insert-port-here> tcp:<insert-same-port-here>

# Install app on your device
react-native run-android

Step 3: Sit back and relax.

# If you run into problems, you may open the developer menu
#  on your device by shaking it (no kidding) or via:
adb shell input keyevent 82

# Put <insert-ip-address-here>:8081 in
#  Dev Settings -> Debug server host & port for device

In which I explore this brave new world

2016-03-23 00:10

Fig. 5: Can you guess what my opinion of Insurgent is?

I got as far as making the GeoCities part of building the UI. Still trying to make sense of the syntax though (and fighting Emacs over indentation). I will continue this for breakfast and will probably finish by noon. Hopefully.

2016-03-24 10:44

Fig. 6: Finally got everything working.

A couple of comments:

  • If you're using Emacs, you will have a hard time with indentation if you use the default JS mode. So do yourself a favour and do a M-x package-install RET js2-mode (available in MELPA).
  • Enable hot reloading. It's hands down the best feature of RN compared to native Android coding (at least, based on the sprinkle of what I know about Android development in general).
  • In retrospect, I should have dived into the docs instead. I really have little patience for copying example code, especially if my goal is to become the person who can write it.
  • I haven't watched Deadpool. Is it as good as they say it is?

I'm going to take a quick break, get some grub, brush my teeth, that sort of thing. Afterwards, I'll probably review JS off-screen and maybe delve into the React.js docs. You know, sit down and actually, properly learn things.

2016-03-23 17:39:

If you're itching to try a new language or are otherwise interviewing for a position you have to bullshit your way through in less than an hour, then Learn X in Y Minutes is a very useful resource.

Still need a few more pumps to get my play-with-and-break-things learning style so I'll be going through another tutorial (this one). The twist? This tutorial was written for iOS. Hopefully by the end of this one I'll know enough of the general landscape to anchor myself while I bungee-jump into the wilderness that is RN (and Android development in general).

2016-03-24 23:38

via Gfycat

Fig. 7: The fruit of many man hours forever lost, like tears...in...rain.

It has taken me most of today to get to this point and most of that was spent on trying to understand the Navigator class. What the flying funk were they thinking?! And the official docs were of little help to novice me either.

A couple of things I discovered:

  • Handling the back button is a mess on Android (and I still have yet to make it work to satisfaction).
  • I should probably misquote Feynman on this one: "If you think you understand JavaScript's this, you don't understand JavaScript's this."
  • With that said, JavaScript Garden has a nice snippet on it, plus on a whole lot of useful gotchas when coding in JS.
  • May I just say what a god-send the app ADV Screen Recorder is? It's probably the most elegantly designed app I've ever used. It just overlays a four-button toolbar on your screen when you want to record something and the layout of its options are to die for. It's as crisp as fresh baguette.

I'll post more screens of experiments and probably upload some code on my GitHubnext time but for now I want to break things! TTFN.

2016-03-25 01:47

I have just discovered how to get rid of those pesky null is not an object errors. Put those goddamn values inside a constructor:

class SomeClass extends Component {
    ...
    constructor() {
        super();
        this.state = {someVar: "someText};
    }
    ...
}

Hopefully I don't commit this mistake ever again.

2016-04-13 08:08

After nearly a month of delay, I finally made headway. I've been trying to get a grips on Realm (a database whose reason for my having picked it has died to entropy) since my last post and only now have I grokked how to get values from its darned [object Object] types.

I went from this:

Fig. 8: If I see one more of this...

To this:

Fig. 9: Yes, I followed React's your-first-baby-steps example to the t yet it still took me until now to get it working.

So what happened? I neglected the fact that this:

// var realm = new Realm({...})
var something = realm.objects('someString');

...returns a list. So all I had to do was access its elements and shoehorn it to a string so I can wrap it under tags:

class someClass extends Component {
    someFunction(object_realm) {
        var string_out = '';
        for(item in object_realm) {
            string_out += item.someProperty.toString();
        }
        return string_out;
    }
    
    render() {
        return (
            ...
                <Text>
                {this.someFunction(something)}
                </Text>
            ...
        );
    }
}

So there you have it. I can finally get values from a database. How funky is that?


Definitions

  • Spelunking series

    in-depth guides about other people's things

  • SR2

    my Android phone's name (yes, I name my devices)

  • RN

    React Native

  • TTFN

    ta-ta for now, i.e. one of the most memorable catchphrases in my childhood