Realtime App Development with RethinkDB and React Native

A realtime app keeps a user up-to-date with the information they want to know, when they need it. A user doesn't need to constantly refresh a window to get the latest updates, a server behind the app will push updates to the app automatically. In this tutorial I'm going to cover realtime app development by creating a news sharing app with RethinkDB and React Native.

I'm going to assume that you already have experience creating React Native apps so I'm not going to go into detail on each line of code. If you're a beginner, I recommend you read my previous tutorial, " Build an Android App with React Native". If you want to follow along, you can find the code on Github.

Here's how the final app will look:

I will start by looking at the code for the mobile app and then move on to the server component which uses Node, Express, Socket.io and RethinkDB.

Install Dependencies

Inside your clone of the project, navigate the NewsSharer directory and execute npm install to install the following dependencies:

After installing the dependencies, there's one extra step to get the icons to work, linking them to the app. Do this by using rnpm, the React Native package manager.

Install rnpm with npm:

npm install rnpm -g

Then execute rnpm link in the root of the NewsSharer directory to link the icons.

This file is the entry-point file for the Android app. If you want to deploy to iOS, you can copy the code into a new index.ios.js file.

The main task of this file does is to import the Main component, where the core of the app is located. This reduces code repetition as you import a component instead of repeating code for each platform.

This is the UserAgent.js file that you see at the root of the NewsSharer directory. It contains code to set the user agent to react-native, needed by Socket.io to work, or it will assume that it's in a browser environment.

window.navigator.userAgent = 'react-native';

Next, the base URL to which the app is going to make requests. If you're testing locally this can be the internal IP address of your computer. For this to work, you have to make sure that your phone or tablet is connected to the same network as your computer.

This function fetches the news items from the server, using the built-in fetch method. It performs a GET request to the news route and then extracts the news_items object from the response. This is then used to create the news datasource which required by the ListView component. Once created, it updates the state with the news datasource so that the UI gets updated with the news items in it.

The componentWillMount method is one of React's lifecycle methods. This allows you to execute code before the initial rendering occurs. This is where you listen for the news_updated event emitted by Socket.io's server component, and when this event happens, it can be one of two things. When a users shares a news item or when they upvote an existing news item.

RethinkDB's changefeed returns a null value for the old_val if it's a new item. This is how you distinguish between the two possibilities. If a user has shared a new news item, push it to the news_items array. Otherwise, look for the upvoted news item and update its upvote count. Now you can update the UI to reflect the changes.

The renderNews function returns the UI for each of the news items. This displays the upvote button, the number of upvotes and the news title. The news title is wrapped inside a TouchableHighlight component. This allows you to execute the openPage function to open the URL. You do the same thing for the upvote count.

Note: The code uses the TouchableHighlight component instead of the Button component because the Button component cannot have View or Text components inside it.

For the body, you have the ListView component for rendering the news items. It has three required parameters, initialListSize, dataSource, and renderRow. The initialListSize is set to 1 so that the ListView renders each row one by one over the course of multiple frames. You can also update this to a higher value if you want the rows to appear all at once. The dataSource are the news items and the renderRow is the function for rendering each individual news item row.

Next is the modal for sharing news. This has two text fields for entering the title and the URL of the news, and a button for submitting it to the server. The text fields uses the TextInput component. There are no labels so add placeholder text to guide the user to what they need to input.

Both text fields have the onChangeText method which updates the value for each one. The keyboardType of url is used for the news URL text field so that it opens the keyboard optimized for entering URL's in the device. The user is not expected to enter it manually, they could use copy and paste, but this is a 'nice to have' in case they decide to enter it manually. Below the text fields is the button for sharing the news. This calls the shareNews function defined earlier.

Creating the Database

Once that's done, you can now access http://localhost:8080 in your browser to view the RethinkDB admin console. Click on the Tables tab then click on the Add Database button. This will open a modal box that lets you enter the name of the database, call it 'newssharer' and click Add.

Now create the table where you're going to save the news items. Click the Add Table button, name it 'news_items', then click Create Table.

Install Dependencies

You can install the server dependencies by navigating to the root of the project directory (with the newssharer-server.js and package.json files), and execute npm install to install the following dependencies:

express: A web framework for Node.js that allows you to create a web server that responds to specific routes.

body-parser: Allows for easy extraction of a JSON string passed along in the request body.

Still inside the database connection code, query the news_items table in the newssharer database, ordering the items by their upvotes count. Then use RethinkDB's Changefeeds feature to listen for changes in the table (a database log of sorts). Every time a change happens in the table (CRUD operations), it's notified of the change.

Inside the callback function for the run method, initialize the socket connection and loop through the contents of the cursor. The cursor represents the changes made in the table. Every time a change occurs, it triggers the cursor.each function.

Note: The function doesn't contain all the data changes. The previous changes gets replaced whenever a new change is made. This means that it only loops through a single row at any given time. This allows you to send the changes to the client using socket.io.

if (err) throw err; //check if there are errors and return it if any io.sockets.on('connection', function(socket){ cursor.each(function(err, row){ if(err) throw err; io.sockets.emit('news_updated', row); }); });

It returns both the whole structure for the old value and the new value of the row. This means you can update more than one field in one client and send those changes to all the other connected clients. RethinkDB makes implementing realtime apps simple with it's changfeeds feature.

The news items are ordered from the highest upvote count to the lowest and limited to 30. Instead of using cursor.each to loop through the news items, use cursor.toArray to convert it to an array with the following structure:

This is called when a user upvotes a news item in the app. It uses the ID of the news item to fetch and then update it.

Note: You've already incremented the upvotes inside the app so are supplying the value that's in the request body.

Test Saving and Upvoting News Items

I've also included a couple of routes for testing saving and upvoting news items. The best time to access these is when the app is already running on your device. That way, you'll see that the UI is updated. How to run the app will be covered in the next section.

Running the Server

At this point I assume that RethinkDB is still running in the background. Run it if it's not already running. Once it's running, execute node newssharer-server.js at the root of the project directory to run the server component of the app.

Running the App

You can run the app the same way you run any React Native app. Below are the links for running the app in the platform of your choice: