Getting started with React Native

Juuso Lappalainen
Junction
Published in
13 min readApr 11, 2018

--

Forget to-do lists — this time we'll be building something truly useless.

This blog post was written for the purposes of a workshop at Stupid Hack, an annual event organised by Junction, where the goal is to create the stupidest and most useless projects imaginable.

The only prerequisite for following this guide is that you have Node installed on your system. Having a physical Android or iOS device to play around with would also be handy, but not necessarily required.

Word of warning: some ability to understand javascript code will be useful. It might be quite hard to follow along if you have never written javascript before.

What we'll be building

I did some research on the current meta for stupid app ideas, and I came across this gem. In short, it's an app that can protect you from the rain if you happen to have forgot your umbrella at home. Sounds perfect, right?

So here's what we want the app to do:

  • Check your location, and query a weather API to see if it's raining
  • Detect the orientation of your phone, and if you're holding it above your head, show an umbrella to keep you dry.

This is actually a cool project, because it lets us use a lot of typical mobile-specific features, like GPS and the accelerometer.

Getting started

Alright, assuming you have Node.js installed, let's create a new React Native project. First, let's install the create-react-native-app command line utility that allows us to quickly create new React Native projects, by opening a terminal window and running:

npm install -g create-react-native-app

With that done, next we'll be creating our new app called StupidApp. Using the utility we installed above, let's run:

create-react-native-app StupidApp 

This should take up to a few minutes, and might display some warnings while it is running, but don't worry about those. Once it's done, you'll notice it has created a new directory, StupidApp, which contains your newly created app.

Next, let's run the development server:

cd StupidApp
npm start

This will start the development server, and your terminal should output something like this:

The development server running in your terminal

Let's run it on a device!

To run the app on an actual device, you'll need to do the following:

  • Download the Expo app from either Google Play Store/App Store, depending on your device.
  • Make sure you are connected to the same Wi-Fi as your computer

Then, open the Expo app, and you'll see an option to scan a QR-code. Choose that, and scan the QR-code printed in your terminal, and after the Javascript bundle has been processed you'll see your app running on your phone!

As long as you have the development server running, whenever you make changes to your code, your app will reload and display the changes immediately! At least it should: if you need to force it to reload, you need to shake your device (quite violently, I might add) to bring up the developer menu.

Word of warning: regarding development, here's a few things you should note:

  • Expect totally random crashes, for no apparent reason, from time to time. In this case, you might need to force close the app and possibly stop and restart your development server to continue. Don't worry, it probably wasn't your fault.
  • In a recent release to React, they have deprecated some methods that React Native still uses. As a result, you'll see warnings in your terminal / app that complain about this issue. Again, you're not doing anything wrong, and they are nothing to worry about. They look like this:

And in your app like this:

To disable these warnings (and all other logging), set development mode off. You can do this by typing d in the terminal window that is running your development server. Note, this means that in case your app crashes, it might not show any errors, but instead just display a blank screen.

The structure of our app

Let's have a quick look at the files that make up our project

  • package.json contains a list of dependencies for your app, as well as some other configuration
  • App.js is your actual app, which is only one js-file at this point

Literally all of the other files/directories you will not need to worry about, as they are mostly not meant to be edited (not for the purposes of this tutorial anyway).

So our entire app at this point is basically contained in App.js. Let's have a look at the code:

At the top, you can see we import React, as well as some components from the React Native package.

After the imports, we define the actual component that will render on screen. A component consists of what we call lifecycle methods, which work exactly the same as in a normal React app. We'll go into a bit more detail on those later, but the most important one is arguably render. Whatever the render function of your component returns is what will be rendered on screen.

In this case we render a View, which is just a wrapper for other components (think of it like a div). Inside the View, we have several Text components. These will, you guessed it: display some text.

Below we define the styles object, which defines the styling of our component. We define a single style, container , which is used to control the arrangement of the Text components inside our View (you can see it's been given the style property of styles.container). In React Native, layouts are defined with flex-box, and style options resemble those used in css. For future reference: The official guide does a good job of explaining flex-box, and a good cheat sheet for the basic styling options can be found here.

Okay, that's enough explanation for now. Let's start building our umbrella app!

Getting the user's location

First, before we try to get the user's location, we'll need a place to store it. A good option for that is the state of our component. Simply put, the state is an object where we can store any data related to the current instance of our component, and it will be cleared when the component is destroyed (i.e. the user no longer sees it).

First, we need to initialize the state. This happens in the constructor of your component, so let's add the following:

When the component is created (i.e. before it is ever shown to the user), the state is initialized with a single property, location, which is null in the beginning.

Let's also edit what our component renders. Before we get the user's location, we'll want to show them that we're in the process of getting it. When we have their location, we can just show it to them for now.

In the render function, we first check if the location we've stored in our state is null. If it is, we call the helper function renderNoLocation which renders a view displaying a loading indicator. The loading indicator is another built-in React Native component, called ActivityIndicator, which we add to our imports at the top. Once your app refreshes, you should now see this:

Actually getting the location

First, we'll need to add imports for the location-related functionality from the Expo package:

import { Constants, Location, Permissions } from 'expo';

Since mobile OS's are quite strict when it comes to requesting things like accessing the user's location, we'll need to ask permission from the user before we can access it. Let's create a single function, getLocation, which first asks for permission, and if the user grants it, get's the location.

Getting a user's location is an asynchronous action, so we'll need to label the function as such, with the async keyword. This lets us use the handy await keyword, which waits for a request to complete before continuing.

Here we also use a new lifecycle method called componentWillMount. Any code in componentWillMount will be run right before the component appears on screen, and as such it will be a good place to start any asynchronous API calls and such.

First, we ask for the user's permission to access their location, which shows the user a dialog. If they accept, we can request their location. Once we have it, we update our state with their new location by calling the built-in setState function of our component.

What this does is it updates the state with the keys that we give it, in this case only location, and leaves everything else in the state untouched.

If you now refresh the app, and grant it permission to access your location, you should see something like this:

Speaking of the state, if we were to now close the app, the state would be cleared and we would no longer have the user's location.

Is it raining?

Now that we have the user's location, let's use it to see if it's raining wherever the user is. We'll use the OpenWeatherMap API for this purpose. Sign up to the service, go to the API Keys section of your profile, and copy your API key.

Since the activation of your key can take up to 10 minutes, let's create our weather service in the meantime.

Create a new file in the root of your project called weather.js. We’ll use the built-in fetch to make our API calls, and our weather service will end up looking something like this:

Our getWeather function returns a Promise, so like before we can use the await keyword to wait for the response. We'll want to get the current weather right after getting the user's location, so let's update App.js accordingly.

First, import our weather service at the top:

import WeatherService from './weather';

Then, we'll add a place for the weather in our state:

Lastly, we'll modify our getLocation function to also get the weather, and store it in the state along with the location:

Now that we have the weather, we'll need to determine what counts as "raining". We can see the response format and what each type of response means here, and we'll determine any 2xx, 3xx or 5xx weather id to count as raining.

Let's add a format function to our weather service to clean up the response of all the data that we wont be using:

Then, let's edit the getLocation function in App.js to just store the formatted version of the weather in the state:

To make sure everything works, edit the render function slightly so it also displays the formatted weather in addition to your location:

Now, assuming everything works, your app will look something like this:

Let's make it (a bit) prettier

If you're not interested in styling, feel free to move on to the next chapter.

Before we move on to using the accelerometer to display an umbrella, we'll make our app a bit prettier to show you what's possible in terms of styling with React Native. Now, I'm no designer, so I'm sure the end result won't be objectively very pretty, but here goes.

We'll start by having our location, whether loading or already retrieved, in a banner at the top. We'll remove the renderNoLocation function from before, and replace it with renderLocation.

Also, to prevent the status bar from appearing on top of our content at the top of the screen, we can import the StatusBar, a hidden component that allows us to do that:

import { StyleSheet, Text, View, ActivityIndicator, StatusBar } from 'react-native';

Now to style this banner of ours, let's edit the styles object below, and add theweatherBanner key. The styles below give it a light background, some padding, and makes it align it's children in a row, centered on both axis'.

But now, if you reload the app, your banner will appear in the center of the screen. Ideally we'd have it at the top, and for that, we'll need to edit the styles of the containing View.

By giving the container these styles, we're telling it to:

  • Align it's children vertically with flexDirection: 'column'
  • In the vertical direction, align children to the top of the screen with justifyContent: 'flex-start'
  • And in the horizontal direction, stretch children to the entire width available with alignItems: 'stretch'

Next, let's display the current weather in the middle of the screen, along with the corresponding weather icon. First, add the Image component to your list of imports from react-native.

We'll add a call to a separate renderWeather function to our render function, like so:

And we'll have the renderWeather function render an icon and description for the current weather:

This might be a good point to experiment with the styling options yourself, but here's my highly inspired design and the corresponding styles:

And finally, the umbrella

Finally, let's tap into the accelerometer of our user's phone, and try to determine which way they are holding their device.

First, we'll again import the relevant module from the expo package:

import { Constants, Location, Permissions, Accelerometer } from 'expo';

The way the accelerometer works, is that we have to subscribe to updates from it. We can, for example, make it give us updates in one second intervals. Let's set up code so that we receive events from the accelerometer, and store the result in the state of our component:

The reason we store our subscription to the accelerometer in a variable is so that we can close it when the component is destroyed — otherwise it might keep running in the background and slow down the performance of your app. Let's make sure we unsubscribe from it in componentWillUnmount, which is called right before the component is destroyed.

So now that we're getting the accelerometer data, what does it mean? The accelerometerData in our state will be updated with an object that contains the x,y and z values of the device's orientation. You can play around with it and see what kind of values it gives for different orientations, but I found that simply checking if the z value is negative is an accurate enough way of checking if the user is holding their phone screen-downwards.

So, when these two conditions are met:

  • It's raining
  • The z value from the accelerometer is negative

…we want to display an umbrella on screen.

Let's add a function for checking whether to show an umbrella or not:

Then, let's render either the weather display or the umbrella, depending on the situation:

For those wondering, the above showUmbrella ? something : other statements are if-else shorthands: if the statement before ? evaluates to true, the whole statement evaluates to something and if not true, to other

Finally, let's create a very simple function for showing the umbrella (image here, just place it in the root of your project):

Now, assuming that it's raining at your current location, you should be able to have a pocket-sized umbrella always with you! Amazing, no?

In case it's not raining, it might be a good idea to just edit the format function of your WeatherService to just always return isRaining: true for testing purposes.

Now, when it's raining and I hold my phone above my head, I'll have my very own umbrella, yay:

Wrapping up

So now we've pretty much created something completely useless, but hopefully in the process ended up learning how fast and easy developing mobile apps with React Native really is.

Thanks for your attention, and I hope you can now build something cool with your newly acquired knowledge!

You'll be able to find the complete code of the finished product, sans my API key, here: https://github.com/hackjunction/stupid-umbrella

--

--