Build an anonymous chat app in React Native
A basic understanding of React and Node.js is needed to follow this tutorial.
In this tutorial, we will be using React Native to build our Android application. React Native let’s you build mobile apps using only JavaScript. It uses the same design as React, letting you compose a rich mobile UI from declarative components. To learn more about React Native, please visit here.
Setting up React Native
First, we need to install the React Native CLI if we don’t already have it. To install React Native, we run:
npm install -g react-native-cli
After installing the CLI, it’s time to create our project. Open up a terminal, and create a new project called pubchat
using the following command:
react-native init pubchat
We wait until React Native does all its installations, then we can change directory into the new project and run the application using the following command:
//change directory to pubchat
cd pubchat
//run the application
react-native run-android
Please note, that before running the run-android
command, you should have an emulator running, or an android device connected via adb
.
You can read more on setting up React Native Android app from https://facebook.github.io/react-native/docs/android-setup.html
At this point, we should see this kind of screen:
However, you may run into an error like this:
To fix the error, all you need to do is to run this command:
react-native start
Setting up Pusher
At this point, React Native is ready and set up. We need to setup Pusher, as well as grab our app credentials.
We need to sign up on Pusher and create a new app, and also copy our secret, application key and application id.
We then need to install the required libraries:
npm install native-base pusher-js pusher express body-parser --save
In the above bash command, we installed 4 packages. I will explain what the four packages do below:
- native-base: An essential cross-platform UI components for React Native. This helps us to reduce time writing and styling UI components ourselves.
- pusher-js: This is the official Pusher JavaScript client. We’ll be using its React Native library to subscribe and listen to events in our application.
- pusher: This is the official Pusher library for Node.js. We will be using Node.js for our API, so this library will come in handy.
- express: This is a Node.js web framework which we’ll use to create our API.
- body-parser: This library is used by Express to parse body requests.
After installing these packages, we need to link them with React Native, so we run the following command:
react-native link
**Please note that because we will be using Fetch to perform AJAX request, we would need to go to our android manifest located in android/app/src/AndroidManifest.xml
and add the following permission: **
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
Creating our API
First, let’s create a new file called server.js
, which serves as our API in our root folder and place in the following contents into it:
// server.js
//require express
var express = require('express')
//define app as in instance of express
var app = express()
//require bosy-parser
var bodyParser = require('body-parser')
//require pusher
var Pusher = require('pusher')
//use bodyparser as a middle ware
app.use(bodyParser.json())
//instantiate pusher
const pusher = new Pusher({
appId: 'XXX_APP_ID',
key: 'XXX_APP_KEY',
secret: 'XXX_APP_SECRET',
cluster: 'XXX_APP_CLUSTER',
encrypted: true
});
//set cors middleware
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
//handle route postfunction
app.post('/', function (req, res) {
pusher.trigger("pubchat", "message_sent", { message : req.body.message, name : "Anonymous" });
res.send({
message:'message_sent'
});
})
//listen on port and serve the app
app.listen(3000, function () {
console.log('Example app listening on port 3000!')
})
The code block above is our Express server setup. At the beginning of the file, we had required Express, Body-parser and Pusher libraries for Node.js respectively. We had also initialized a new Pusher object, passing in our appId
, key
, secret
to it, and we set the output of the object to a constant called pusher
.
Next, we set the CORS header to our request, using a middleware function.
Finally, we create a post handler for the \
route, and we then make a Pusher
trigger to a channel called pubchat
with an event called message_sent
.
Let’s take note of both the channel name and the event name used on this server. The channel name will be subscribed to, while we will listen for the event in our React Native app.
This is all we need at the server side for our API call to work.
Next, we go to our command line and run:
node server.js
Crafting up the application
Now let’s replace our index.android.js
with the following:
// index.android.js
/**
* Sample React Native App
* https://github.com/facebook/react-native
* @flow
*/
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
TextInput,
ScrollView
} from 'react-native';
// import native base components
import { Container, Content, Footer, Button} from 'native-base';
//import pusher
import Pusher from 'pusher-js/react-native'
//react-native class
export default class pubchat extends Component {
//load constructor
constructor(props){
super(props);
//declare an array of messages
var messages_array = [];
// declare initial states
this.state ={
messages_array,
text:''
}
//instantiate pusher
var pusher = new Pusher('XXX_APP_KEY', {
cluster: 'XXX_APP_CLUSTER'
});
//subscribe to the public chat channel
var my_channel = pusher.subscribe('pubchat');
//bind and listen for chat events
my_channel.bind("message_sent", (data)=> {
this.state.messages_array.push(data);
this.setState({
text:''
})
});
}
//function that sends messahe
send_message(){
//check that the text input isnt empty
if(this.state.text !=""){
fetch('XXX_IP_TO_MY_ROUTE', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
message: this.state.text
})
})
.then((response) => response.json())
.then((responseJson) => {})
.catch((error) => { console.error(error); });
}
}
//function that loops over our messages and displays them
loop(){
var element = [];
for (var index = 0; index < this.state.messages_array.length; index++) {
element.push(<View key={"container"+index} >
<Text key = {"author"+index}>
{this.state.messages_array[index].name}
</Text>
<Text key = {index} style={styles.bubble_you} >
{this.state.messages_array[index].message}
</Text>
</View>);
}
return element;
};
//render function that actually shows the page
render() {
//execute the loop function and store its response into a variable
myloop = this.loop();
return (
<Container>
<ScrollView >
<View style={styles.container}>
<Text style={styles.welcome}>
Welcome to the public chat room!
</Text>
{myloop}
</View>
</ScrollView>
<Footer >
<TextInput
value ={this.state.text}
style={{width: '80%'}}
placeholder="Enter Your message!"
onChangeText={(text) => this.setState({text})}
/>
<Button onPress={()=> this.send_message()}>
<Text>Send</Text>
</Button>
</Footer>
</Container>
);
}
}
//stylesheet
const styles = StyleSheet.create({
container: {
flex: 1,
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
bubble_you: {
color: '#fff',
backgroundColor: '#00b0ff',
width: '50%',
borderRadius: 25,
padding: 7,
marginBottom: 2,
},
});
AppRegistry.registerComponent('pubchat', () => pubchat);
Above, we have imported the Native Base component to help us with our UI styling instead of the default React Native components. Next, we imported Pusher for React Native, then we declare our React Native class.
We proceed by creating a constructor, and in our constructor, two states are declared namely: messages_array
and text
, which respectively represent our array of messages as well as the current text that is being typed.
Next, we instantiate Pusher, passing in our APP_KEY
. Then we subscribe to the channel which we are emitting to from the server called pubchat
and also we listen to the message_sent
event which we also trigger from our server.
While listening to the message_sent
event, we push the data that arrives at our messages_array
state, and also set our text
state to empty.
Next, we create a function which sends our messages to the server, so it can be sent to Pusher. In this function, we first check if the state is empty, to avoid sending empty messages to the server.
Next, we use the fetch
API provided by React Native to send an AJAX request to our server which we created earlier.
Note: If you use IP address such as 127.0.0.1
or localhost
, the request is most likely going to fail. This is because, in React Native, localhost
or 127.0.0.1
refers to the internal application. Please use the network IP for your system instead.
Next, we define a loop
function, which loops through all our messages and pushes them into an array which is being returned. This function would be used to display all messages on the UI.
The next function is our render
function, which is a native React Native function. First, we declare a variable called myloop
and set it to our loop
function.
In our return statement, the myloop
variable was rendered, so it can display its content. Also, take a look at the footer
tag we have there. In the footer
tag, we have a text input
and a button
.
The text input text is used to set the text
state anytime the text changes using the onChangeText
event of the button. Notice that our button also calls the send_message
function anytime it is pressed by binding it to its onPress
function.
Finally, we defined some style sheets.
At this point if we reload our application, our app would look like the following:
At this point, once our server is up and running, we should go to the application, type in a message, then send.
Here is a demo of what we have built:
Conclusion
In this article, we have demonstrated how to make a public anonymous chat application in Android using React Native. We have secured the design choices which are important to begin with, and the cases above ought to help you fill in the holes and give an outline of a portion of the other design choices accessible to you.
28 April 2017
by Chimezie Enyinnaya