fbpx

Blogs from the Ranch

< Back to Our Blog

Live Updates With Queues, WebSockets, and Push Notifications. Part 2: React Native Apps with Expo

In part 1 of our series, we created a Node.js backend for our Notifier app that receives messages via a webhook and sends them over a RabbitMQ queue to a worker process, which then saves them to a MongoDB database. This is a good foundation for our Node backend upon which we’ll be able to add live updates in future posts.

Before we do any more work on the backend, let’s create a React Native client app using Expo so we’ll have a frontend that’s ready for a great live-update experience as well. One of Expo’s features is great cross-platform push notification support, so we’ll be able to benefit from that in part 6 of the series.

If you like, you can download the completed client project for part 2.

Setting Up the Project

If you haven’t built an app with Expo before, this tutorial will walk you through running the app on a virtual device on either Android or iOS. You will need to have one of the following installed on your development machine:

Next, install the Expo CLI globally:

$ npm install -g expo-cli

Then create a new project:

$ expo init notifier-client

You’ll be prompted to answer a few questions; choose the following answers:

  • Choose a template: blank
  • Name: Notifier
  • Slug: notifier-client
  • Use Yarn to install dependencies? Y

After the project setup completes, go into the project directory and add a few more dependencies:

$ cd notifier-client
$ yarn add axios react-native-elements

Here’s what they’re for:

  • axios is a popular HTTP client.
  • react-native-elements is a UI library that will make our super-simple app look a bit nicer.

Next, let’s start the Expo development server:

$ yarn start

 

This should open Expo’s dev server in your browser. It looks something like this:

metro bundler

If you want to run on Android, make sure you’ve followed Expo’s instructions to start an Android virtual device. If you want to run on iOS, Expo will start the virtual device for you.

Now, in the browser window click either “Run on Android device/emulator” or “Run on iOS Simulator.” In the appropriate virtual device you should see a build progress bar and, when it completes, the message “Open up App.js to start working on your app!”.

default screen android and ios

Let’s do that thing they just said!

Loading Data From the Server

Replace the contents of App.js with the following:

import React, { Fragment } from 'react';
import { SafeAreaView, StatusBar } from 'react-native';
import { ThemeProvider } from 'react-native-elements';
import MainScreen from './src/MainScreen';

export default function App() {
  return (
    <ThemeProvider>
      <Fragment>
        <StatusBar barStyle="dark-content" />
        <SafeAreaView style={{ flex: 1 }}>
          <MainScreen />
        </SafeAreaView>
      </Fragment>
    </ThemeProvider>
  );
}

Note that at this point the React Native app won’t build for a few steps.

The changes to App.js will do the following:

  • Hooks up React Native Elements’ ThemeProvider so we can use Elements.
  • Sets up a top status bar.
  • Confines our content to the safe area of the screen, so we don’t overlap hardware features such as the iPhone X notch.
  • Delegates the rest of the UI to a MainScreen component we haven’t created yet.

Now let’s create that MainScreen component. Create a src folder, then a MainScreen.js inside it, and add the following contents:

import React from 'react';
import { View } from 'react-native';
import MessageList from './MessageList';

export default function MainScreen() {
  return (
    <View style={{ flex: 1 }}>
      <MessageList />
    </View>
  );
}

This file doesn’t do much yet; we’ll add more to it in a future post. Right now it just displays a MessageList we haven’t created yet. On to that component!

Create src/MessageList.js and add the following:

import React, { useState, useEffect } from 'react';
import { FlatList, Platform, View } from 'react-native';
import { ListItem } from 'react-native-elements';
import axios from 'axios';

const httpUrl = Platform.select({
  ios: 'http://localhost:3000',
  android: 'http://10.0.2.2:3000',
});

const loadInitialData = async setMessages => {
  const messages = await axios.get(`${httpUrl}/list`);
  setMessages(messages.data);
};

export default function MessageList() {
  const [messages, setMessages] = useState([]);

  useEffect(() => {
    loadInitialData(setMessages);
  }, []);

  return (
    <View style={{ flex: 1 }}>
      <FlatList
        data={messages}
        keyExtractor={item => item._id}
        renderItem={({ item }) => (
          <ListItem
            title={item.text}
            bottomDivider
          />
        )}
      />
    </View>
  );
}

Here’s what’s going on here:

  • In our component function, we set up a messages state item.
  • We set up an effect to call a loadInitialData function the first time the component mounts. We pass it the setMessages function so it can update the state.
  • loadInitialData makes a web service request and stores the data in the response. The way to make HTTP requests to your local development machine differs between the iOS Simulator (http://localhost) and Android Emulator (http://10.0.2.2), so we use React Native’s Platform.select() function to return the appropriate value for the device we’re on.
  • We render a FlatList which is React Native’s performant scrollable list. The list contains React Native Elements ListItems. For now we just display the text of the message.

Run the following command in the Node app folder to take sure our notifier Node app from part 1 is up:

$ node web

Reload our Expo app on the virtual device:

  • In the Android Emulator, press Command-M to bring up the developer menu, then tap “Reload”.
  • In the iOS Simulator, press Command-Control-Z to bring up the developer menu, then tap “Reload JS Bundle”.

When the app reloads, you should see a list of the test messages you entered on your server:

messages on phone

What’s Next?

With this, the basics of our client app are in place, and we’re set to begin adding live updates across our stack. In the next part we’ll introduce WebSockets that allow us to push updates to the client.

Not Happy with Your Current App, or Digital Product?

Submit your event

Let's Discuss Your Project

Let's Discuss Your Project