React Native: Chat Application

We build a chat application made in React Native using Google Firebase, React Navigation, and Gifted Chat.

Platypus
10 min readJan 3, 2019

Let’s build a chat application.

The goal is to create an application with: authentication (signup/login), chat room creation, and group messages within those rooms.

It will be built in React Native. Firebase will be used to handle authentication and database storage. React Navigation will help with getting around. And, Farid Safi’s wonderful Gifted Chat library will handle the actual chat screen.

In the interest of space, and keeping things clean all styles will be kept out of this write up but live in the GitHub repository.

Create the App and install Dependencies

Open a terminal window, navigate to your folder of choice, and invoke the React Native CLI to create a new application named “RNFirebaseChat”.

Once the application is set up, navigate into the folder and use npm to install the project dependencies.

# Create a new React Native App
react-native init RNFirebaseChat
cd RNFirebaseChat
# Install dependencies from npm
npm install —-save firebase react-navigation react-native-gifted-chat

As a final bit here, duplicate “index.ios.js” as a new file called “app.js” in the main directory. Then import that file in both the “index.ios.js” and “index.android.js” files.

https://gist.github.com/ridgeO/1f609e13227aee5f5b2b23c9cc35c451.js?file=01.js

This will set up the application to be cross platform from the start.

Now is a good time to check that everything is working as desired. Spin up the applicaiton in either an iOS or Android simulator.

# Open an iOS simulator
react-native run-ios
or# Open an Android simulator
react-native run-android

Firebase Setup

Firebase is going to handle authentication and database storage for the application.

To get it set up, head over to https://firebase.google.com and sign in using your Google account. Then open up the console and add a new project with your preferred name and region.

Back in your React Native app, create a new folder, “components” to house all of the component files. Then in that folder, create “firebaseConfig.js” to store your Firebase project credentials.

If you’re using version control like “git”, add this file to your ignore list to keep it private.

https://gist.github.com/ridgeO/1f609e13227aee5f5b2b23c9cc35c451.js?file=02.js

With that, the Firebase project will now be accessible through the “firebaseApp” const in the application.

Users

For this app, basic email/password authentication will be used for creating and signing in users.

To do this, start at the Firebase console and select your project. On the left hand navigation menu, select the “Authentication” option. Then press the button that says “Set Up Sign-In Method”.

Select the option for Email/Password, and slide the toggle to enable it. Once enabled, Firebase is ready to create and sign in users using an email/password combination. Wonderfully simple.

Now to set up user creation and sign in paths in the application. Create a new file in the “components” folder for “SignUp.js”.

https://gist.github.com/ridgeO/1f609e13227aee5f5b2b23c9cc35c451.js?file=03.js

This adds a basic sign up screen with email and password fields as well as some Platypus styling.

To see it, the screen needs to be added to the application. This is a good time to set up navigation for the app as well. In “app.js” set up a “StackNavigator”.

https://gist.github.com/ridgeO/1f609e13227aee5f5b2b23c9cc35c451.js?file=04.js

This creates a StackNavigator component, adds a route for the SignUp screen and then registers it as the root of the the application. Now if you refresh the app, the “SignUp” screen should appear.

The “SignUp” screen has inputs for email/password and buttons for pressing to Sign Up and Sign In, but they’re not backed by anything right now.

Open “SignUp.js” and inside the “SignUp” class under the “navigationOptions” object, set up a constructor.

https://gist.github.com/ridgeO/1f609e13227aee5f5b2b23c9cc35c451.js?file=05.js

This adds fields to the “SignUp” component’s state that we can use to store the user’s email and password respectively. Now, add a “signUp” function bellow the constructor.

https://gist.github.com/ridgeO/1f609e13227aee5f5b2b23c9cc35c451.js?file=06.js

There’s a lot going on here.

The “async” keyword queues up an async function that will automatically return promises that are resolved with function’s return value. It also enables the use of “await” which will temporarily exit the function until a given task is completed.

A quick “if statement” is used to determine that neither email or password fields are left blank, and triggers an alert to the user if they are.

Inside of that, there’s a “try/catch statement” wrapping the actual user creation code. If you break it down, the line that really matters here is “await firebaseApp.auth().createUserWithEmailAndPassword(this.state.userEmail, this.state.userPassword);”. It connects to Firebase using the “firebaseApp” variable, and passes in the state values for user email/password to create a new user.

Authentication with Firebase is asynchronous, so the use of the “await” keyword here tells the program to temporarily exit the function until the user creation promise is returned from Firebase.

Of course, in its current state the function is not doing anything. Hook it up to the “Sign Up” button by adding an “onPress” prop to the view’s TouchableHighlight component.

https://gist.github.com/ridgeO/1f609e13227aee5f5b2b23c9cc35c451.js?file=07.js

Refresh the app and give it a try. An alert should pop up informing you that the email/password fields cannot be blank, even if you fill in the text inputs.

That’s because the email/password fields are blank in the component’s state. The same state which the “signUp” function pulls from.

Add some “onChangeText” props to the inputs so that the state values are updated when new text is entered.

https://gist.github.com/ridgeO/1f609e13227aee5f5b2b23c9cc35c451.js?file=08.js

Refresh the app, enter a test email/password, and try signing up again. The first time you press the button, nothing should happen. However, if you try to sign up again, an alert will pop up with the error “The email address is already in use by another account.” displayed.

Head over to the Firebase console and under “Authentication > Users” should be the new user account you just created. Pretty cool.

It’s time to set up a way for existing users to sign in. Duplicate “SignUp.js”, name the copy “SignIn.js” and make a few tweaks to the code.

https://gist.github.com/ridgeO/1f609e13227aee5f5b2b23c9cc35c451.js?file=09.js

All instances of “Sign Up” are swapped for “Sign In” including function names, but not much else changes.

The exception to this is in the “signIn” function. Where before there was “.createUserWithEmailAndPassword()” now the “.signInWithEmailAndPassword()” function is used.

Add the “SignIn” screen to the “RootNavigator” in “app.js” by importing it at the top and then creating a new route. Place it first on the list so that it renders before “SignUp” improving the experience for return users.

https://gist.github.com/ridgeO/1f609e13227aee5f5b2b23c9cc35c451.js?file=10.js

Once that’s set up, add some functions to “SignIn” and “SignUp” so that users can easily navigate between them using the TouchableHighlights at the bottom. In “SignIn.js” add a “goToSignUp” function between the “signUp” and “render” functions. Then connect it to the TouchableHighlight at the bottom via the “onPress” prop.

https://gist.github.com/ridgeO/1f609e13227aee5f5b2b23c9cc35c451.js?file=11.js

Do the same in “SignUp.js” except using the “goBack” function built into React Navigation.

https://gist.github.com/ridgeO/1f609e13227aee5f5b2b23c9cc35c451.js?file=12.js

Refresh the app. You should now be able to switch between the “SignIn” and “SignUp” screens.

Rooms

Once authenticated, users will be taken to a landing page that lists a number of chat rooms, and also has an input they can use to create a new room.

Add “Rooms.js” to the components folder.

https://gist.github.com/ridgeO/1f609e13227aee5f5b2b23c9cc35c451.js?file=13.js

The “Rooms” screen is pretty straightforward with the exception of the FlatList component. It’s a handy component you can read more about here.

For this application what you need to know is that the “renderRow” function is being used by the FlatList to format the array of data which is passed to it. More on that later.

Import “Rooms.js” and add a route to the “RootNavigator” in “app.js” for it.

https://gist.github.com/ridgeO/1f609e13227aee5f5b2b23c9cc35c451.js?file=14.js

Then add a call to the “navigate” function as part of the “signUp/signIn” functions in “SignIn.js” and “SignUp.js”.

https://gist.github.com/ridgeO/1f609e13227aee5f5b2b23c9cc35c451.js?file=15.js

Refresh the app and sign in. You should be taken to the “Rooms” screen. There’s an input and a create button, but no way to create a room or view rooms already created.

Set up a constructor for the component state and a reference to the Firebase project’s database.

https://gist.github.com/ridgeO/1f609e13227aee5f5b2b23c9cc35c451.js?file=16.js

A variable is set to reference the Firebase project’s database, this is further set to reference the “Rooms” listing in that database. State values are aslo set for rooms, and newRoom as an empty array and string respectively.

Bellow the constructor, set up a function to watch for changes made to the database, and pull information from it as needed.

https://gist.github.com/ridgeO/1f609e13227aee5f5b2b23c9cc35c451.js?file=17.js

Here the life cycle function “componentWillMount” is used to kickoff another custom function “listenForRooms”. This second function uses the variable defined in the constructor to check the realtime database specifically under the “rooms” category. It will pull every entry under the rooms category and then add them to the “FBrooms” array variable. This array is then set as the new “rooms” state. This function will allow for fetching the initial list of established rooms as well as updating the component when new rooms are added.

To add new rooms, add another function under the “listenForRooms” function.

https://gist.github.com/ridgeO/1f609e13227aee5f5b2b23c9cc35c451.js?file=18.js

“addRoom” starts with a check to see if the “newRoom” has a name. Provided the name is not blank, a new room is created by pushing the room object to the database. Then the “newRoom” state is set back to an empty string to clear the text input.

With the functions set up it’s time to to incorporate them into the rendered components.

The text input should get an “onChangeText” prop to update the state value of “newRoom”, and a “value” prop to match the new state. That and an “onPress” prop added to the “create” button will take care of adding rooms to the database.

Finally, pass in the “rooms” state to the FlatList “data” prop to pull in the list of rooms retrieved from the database.

https://gist.github.com/ridgeO/1f609e13227aee5f5b2b23c9cc35c451.js?file=19.js

Refresh the app, and sign in. You should be able to add new rooms, and see them populate the list in real time.

Messages

Farid Safi’s wonderful chat UI library, Gifted Chat is going to be the basis for this component.

It’s an awesome package that comes packed with a ton of features. This tutorial is barely going to scratch the surface of what is available. I highly encourage you to check out the documentation and play around with it some.

Aside from the use of Gifted Chat, this is going to follow a very similar format to the “Rooms” component. There will be a call to Firebase which will set the current state and then update the rendered screen accordingly.

Kick things off by adding “Messages.js” to the components folder.

https://gist.github.com/ridgeO/1f609e13227aee5f5b2b23c9cc35c451.js?file=20.js

Aside from the addition of Gifted Chat to the imports list, the navigation options static for this one is a bit different as it’s the first in which the header is actually used. A room name is supplied in the title, and the other bits are just styling.

The entire render section comes from Gifted Chat. It’s going to handle setting up a text input, send button, and a tasteful display of messages. All that it needs is some data passed to it.

Import “Messages.js” into “app.js” and add it to the “RootNavigator”.

https://gist.github.com/ridgeO/1f609e13227aee5f5b2b23c9cc35c451.js?file=21.js

Then, in “Room.js” add the function “openMessages” to the “onPress” prop of each room entry.

https://gist.github.com/ridgeO/1f609e13227aee5f5b2b23c9cc35c451.js?file=22.js

The “openMessages” function is passed a room argument. This in turn is broken down into an object containing the room’s key (id generated by Firebase), and name. These values are then passed on to the new screen as a navigation params object. It’s one of the many cool features included with React Navigation

With navigation set up, and the room key successfully passed through to the “Messages” component, it’s time to connect to the firebase project. Add a constructor to the “Messages” class under the “navigationOptions” static.

https://gist.github.com/ridgeO/1f609e13227aee5f5b2b23c9cc35c451.js?file=23.js

A small tweak to the “navigationOptions” is made to have the screen title reflect the room name, and a number of variables are defined. Most of note here is the use of the navigation params to define room key. This key sets the reference in the database to collect all messages under the same group id.

With those variables defined, add in a functions for retrieving messages from the database after the constructor.

https://gist.github.com/ridgeO/1f609e13227aee5f5b2b23c9cc35c451.js?file=24.js

Just as in “Rooms.js”, a life cycle function is used to trigger a custom function that loads existing messages from the database. Differently here, while iterating through the data snapshot to reorganize message data, the structure is dictated by the “GiftedChat” component. Also of note here is a cool syntax for prepending to an array “[… existingArray]”. This is done to ensure the ordering of messages is preserved and new messages populate to the bottom of the screen instead of the top.

Similarly, the “addMessage” function must be arranged to accommodate the “message” object passed to it by “GiftedChat”. A “created at” value is derived using a “date” function to supply context for message ordering, and a user object is stored with id and name.

https://gist.github.com/ridgeO/1f609e13227aee5f5b2b23c9cc35c451.js?file=25.js

The last thing to do is to connect the “GiftedChat” component to the data harvested from Firebase and the “addMessage” function.

https://gist.github.com/ridgeO/1f609e13227aee5f5b2b23c9cc35c451.js?file=26.js

With that, the application is finished.

Refresh the app, sign in, open a room and try sending a few messages. Then go back, create some new accounts to view and add more messages. Gifted Chat will organize everything into a nice clean chat display.

Thanks for reading! Join us next time for more development tutorials, tips, and tricks.

Follow us on Twitter to get updated when a new Platypost is released.

GitHub Gists and Repo

All of the GitHub Gists for this tutorial can be found here and the Repo is here.

--

--

Platypus

Development studio combining quality tech and good design into uniquely functional tools that empower your business. https://platypus.dev