Build a chat app with react-native-gifted-chat
Tags: reactnative, mobile, firebase
Published: 2021-09-03 18:53:09

**Written by [Emmanuel Etukudo](https://blog.logrocket.com/author/emmanueletukudo/)** ✏️

As the demand for real-time communication grows, developers are looking for easy ways to add reliable communication channels to mobile apps. In this tutorial, we’ll learn how to build mobile chat apps for both iOS and Android in React Native using [react-native-gifted-chat](https://github.com/FaridSafi/react-native-gifted-chat), a chat UI designed to empower app developers to build cross-platform chat apps. 

To follow along with this tutorial, you’ll need:

*   Familiarity with CSS, HTML, and Javascript ES6
*   Node.js and Watchman installed on your development machine
*   iOS Simulator or Android Emulator for testing
*   A code editor installed in your development machine
*   A basic understanding of React and React Native

Let’s get started!

## react-native-gifted-chat props

Let’s take a look at a few of the built-in props we’ll use to create our application:

*   `messages` (array): displays messages
*   `text` (string): the type of input text. Default is `undefined`
*   `isTyping` (bool): handles the typing indicator state. Default is `false`
*   `timeFormat` (string): determines time format. Default is `LT`
*   `dateFormat` (string): determines date format. Default is `ll`
*   `placeholder` (text): the placeholder for an empty text field. Default is `Type a message...`
*   `user` (object): the credentials of the user sending the message, i.e., `{_id, name, avatar}`
*   `messageIdGenerator` (function): generates an id for each new message. Default is `UUID` `V4`

You can explore other props in the [documentation](https://github.com/FaridSafi/react-native-gifted-chat#readme).

## Installing react-native-gifted-chat

Let’s start by setting up a new React Native app. Open your terminal, navigate into your working directory, and run the command below to initialize a new React Native app:

```bash
npx react-native init GiftedChatApp
```

Once setup is complete, navigate into the `GiftedChatApp` directory and run the command below to install the required dependencies:

```bash
cd GiftedChatApp && npm install @react-navigation/native @react-navigation/stack react-native-gifted-chat react-native-reanimated react-native-gesture-handler react-native-screens react-native-safe-area-context @react-native-community/masked-view
```

The command above will install React Navigation, react-native-gifted-chat, and the other required dependencies in your project. If you have everything set up correctly, your app should look like the screenshot below: 

![React Native Gifted Chat Dependencies](https://blog.logrocket.com/wp-content/uploads/2021/08/react-native-gifted-chat-dependencies.png)

## Building the login screen

Before we begin building the login screen, let’s update our code to make `App.js` allow screen navigation. Open `App.js`, then copy and paste the code below:

```JSX
/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 *
 * @format
 * @flow strict-local
 */
import React from 'react';
import {
  StyleSheet,
} from 'react-native';
import {createStackNavigator} from '@react-navigation/stack'
import {NavigationContainer} from '@react-navigation/native';
import LoginScreen from './screens/Login';
const Stack = createStackNavigator();
const App = () => {
  return (
    <NavigationContainer>
      <Stack.Navigator >
        <Stack.Screen name="Login" component={LoginScreen} />
      </Stack.Navigator>
    </NavigationContainer>
  );
};
const styles = StyleSheet.create({
})
export default App;
```

Let’s install one final dependency. React Native Elements is a UI toolkit that allows you to easily create form elements and icons. To install React Native Elements, run the code below in your terminal:

```bash
npm install react-native-elements
```

Next, navigate into your project directory, create a new folder named `screens`, create a new file named `Login.js`, then copy and paste the code below in `Login.js`:

```JSX
import React, { useState } from 'react';
import { View, StyleSheet } from 'react-native'
import {Input, Button} from 'react-native-elements';
import Icon from 'react-native-vector-icons/FontAwesome';

const Login = () => {
    const [email, setEmail] = useState('');
    const [password, setPassword] = useState('');
    return (
        <View style={styles.container}>
            <Input
                placeholder='Enter your email'
                label='Email'
                leftIcon={{ type: 'material', name: 'email' }}
                value={email}
                onChangeText={text => setEmail(text)}
            />
            <Input
                placeholder='Enter your password'
                label='Password'
                leftIcon={{ type: 'material', name: 'lock' }}
                value={password}
                onChangeText={text => setPassword(text)}
                secureTextEntry
            />
            <Button title="sign in" style={styles.button} />
            <Button title="register" style={styles.button} />
        </View>
    )
}
const styles = StyleSheet.create({
    container: {
        flex: 1,
        alignItems: 'center',
        padding: 10,
        marginTop: 100,
    },
    button: {
        width: 370,
        marginTop: 10
    }
});
export default Login;
```
In the code block above, we imported the `useState()` Hook, created two states to store `email` and `password` fields, created the login input fields using React Native Elements, and finally added styles. Now, run `npx react-native run-ios`, and your app should look like the image below: ![Install React Native Elements Gifted Chat](https://blog.logrocket.com/wp-content/uploads/2021/08/install-react-native-elements-gifted-chat.png)

## Building the registration screen

Now, let’s build a registration screen to add new users to our application. Navigate into the `screens` folder, create a new file named `Register.js`, then copy and paste the code below:

```JSX
import React, { useState } from 'react';
import {View, StyleSheet} from 'react-native'
import { Input, Button } from 'react-native-elements';

const Register = () => {
    const [name, setName] = useState('');
    const [email, setEmail] = useState('');
    const [password, setPassword] = useState('');
    const [avatar, setAvatar] = useState('');
    return (
        <View style={styles.container}>
            <Input
                placeholder='Enter your name'
                label='Name'
                value={name}
                onChangeText={text => setName(text)}
            />
            <Input
                placeholder='Enter your email'
                label='Email'
                value={email}
                onChangeText={text => setEmail(text)}
            />
            <Input
                placeholder='Enter your password'
                label='Password'
                value={password} onChangeText={text => setPassword(text)}
                secureTextEntry
            />
            <Input
                placeholder='Enter your image url'
                label='Profile Picture'
                value = {avatar}
                onChangeText={text => setAvatar(text)}
            />
            <Button
                title="register" style={styles.button}
            />
        </View>
    )
}
const styles = StyleSheet.create({
    container: {
        flex: 1,
        alignItems: 'center',
        padding: 10,
        marginTop: 100,
    },
    button: {
        width: 370,
        marginTop: 10
    }
})
export default Register;
```

## Setting up Firebase for React Native

Now that you are done building the login and registration screens, let’s add Firebase to our application to authenticate users. 

Install Firebase by running the code below:

```bash
npm install --save @react-native-firebase/app
```

Now, head to the [Firebase website](https://firebase.google.com) and create a new project called Gifted Chat App: 

![Firebase Project New React Native Project](https://blog.logrocket.com/wp-content/uploads/2021/08/firebase-project-new-react-native-project.png) 

Next, we’ll add a web app to the Firebase project we just created. Create a new file called `firebase.js` in the root directory of the project. Copy the `firebaseConfig` credentials from the screen below: 

![Firebase Config Credentials Add Web App](https://blog.logrocket.com/wp-content/uploads/2021/08/firebase-config-credentials-add-web-app.png) 

Replace the credentials currently in `firebaseConfig` with your project’s unique details:

```JSX
import * as firebase from 'firebase';
import 'firebase/auth';
import 'firebase/firestore';

var firebaseConfig = {
    apiKey: "your_api_key",
    authDomain: "your_auth_domain",
    projectId: "your_project_id",
    storageBucket: "your_storage_bucket",
    messagingSenderId: "your_meddage_sender_id",
    appId: "your_app_id"
};

let app;
if (firebase.apps.length === 0) {
    app = firebase.initializeApp(firebaseConfig);
} else {
    app = firebase.app();
}
const db = app.firestore();
const auth = firebase.auth();
export { db, auth };
```

## Authenticating a user with Firebase

Let’s enable user [authentication through Firebase](https://blog.logrocket.com/storing-retrieving-data-react-native-apps-firebase/) using `email` and `password`. Click **authentication** from the sidebar menu of the Firebase console and select `Email/Password`. Next, select **enable** and **save**: 

![Add Authentication Firebase](https://blog.logrocket.com/wp-content/uploads/2021/08/add-authentication-firebase.png) 

Now that the Firebase setup and configuration are complete, let’s update the `Register.js` file to authenticate a new user. Copy the code below and place it above the `return` function:

```JSX
// ... 
const register = () => {
        auth.createUserWithEmailAndPassword(email, password)
            .then((userCredential) => {
                // Signed in 
                var user = userCredential.user;
                // ...
                user.updateProfile({
                    displayName: name,
                    photoUrl: avatar ? avatar : "https://gravatar.com/avatar/94d45dbdba988afacf30d916e7aaad69?s=200&d=mp&r=x",
                })
                    .catch((error) => {
                        alert(error.message)
                    })
            })
            .catch((error) => {
                var errorCode = error.code;
                var errorMessage = error.message;
                // ..
                alert(errorMessage);
            });
    }
//...
```

First, we imported the `auth` object from the `firebase.js` file we created earlier. Next, we created a register function and passed the new user’s email and password to the `signInWithEmailAndPassword` method. Finally, we updated the user’s credentials with `name` and `avatar`. 

Next, we’ll pass the register function to the register button with the `onPress` handler:

```JSX
<Button title="register" onPress={register} style={styles.button} />
```

Now, you can register a new user from your app and list them in your Firebase console: ![Register New User Firebase](https://blog.logrocket.com/wp-content/uploads/2021/08/register-new-user-firebase.png)

## Building the chat screen

Next, we’ll build the chat screen, where we’ll redirect users after a successful login. 

Create a new file called `Chat.js` in the `screens` directory. To create a basic chat app, copy and paste the code below into the file:

```JSX
import React, { useEffect, useCallback, useState, useLayoutEffect } from 'react';
import { View, Text, StyleSheet, TouchableOpacity } from 'react-native';
import { Avatar } from 'react-native-elements';
import { auth } from '../firebase';
import { GiftedChat } from 'react-native-gifted-chat';

const Chat = ({ navigation }) => {
    const [messages, setMessages] = useState([]);
    const signOut = () => {
        auth.signOut().then(() => {
            // Sign-out successful.
            navigation.replace("Login");
        }).catch((error) => {
            // An error happened.
        });
    }
    useLayoutEffect(() => {
        navigation.setOptions({
            headerLeft: () => (
                <View style={{ marginLeft: 20 }}>
                    <Avatar
                        rounded
                        source={{
                            uri: auth?.currentUser?.photoURL,
                        }}
                    />
                </View>
            ),
            headerRight: () => (
                <TouchableOpacity style={{
                    marginRight: 10
                }}
                    onPress={signOut}
                >
                    <Text>logout</Text>
                </TouchableOpacity>
            )
        })
    }, [navigation]);

    useEffect(() => {
        setMessages([
            {
                _id: 1,
                text: 'Hello developer',
                createdAt: new Date(),
                user: {
                    _id: 2,
                    name: 'React Native',
                    avatar: 'https://placeimg.com/140/140/any',
                },
            },
        ])
    }, [])
    const onSend = useCallback((messages = []) => {
        setMessages(previousMessages => GiftedChat.append(previousMessages, messages))
    }, [])
    return (
        <GiftedChat
            messages={messages}
            showAvatarForEveryMessage={true}
            onSend={messages => onSend(messages)}
            user={{
                _id: auth?.currentUser?.email,
                name: auth?.currentUser?.displayName,
                avatar: auth?.currentUser?.photoURL
            }}
        />
    );
}
const styles = StyleSheet.create({
});
export default Chat;
```
With the Firebase `auth` object, we created the `messages` state and a function to handle a user logging out. Next, we created a basic navigation effect by wrapping the header `nav` with a `useLayoutEffect`. 

With the `useEffect` Hook, we created a dummy message, which we mounted onto the `GiftedChat` component. The user prop on the `GiftedChat` component refers to the user who is currently logged in, which in this case is you. 

Now, your app should look like the screenshot below: 

![React Native Gifted Chat Dummy Message](https://blog.logrocket.com/wp-content/uploads/2021/08/react-native-gifted-chat-dummy-message.png) 

Currently, the messages in our chat app aren’t stored anywhere. To store messages in `firestore`, we’ll modify the `onSend` function:

```JSX 
const onSend = useCallback((messages = []) => {
        setMessages(previousMessages => GiftedChat.append(previousMessages, messages))
        const { _id, createdAt, text, user,} = messages[0]
        db.collection('chats').add({ _id, createdAt,  text, user })
    }, []);
```

To retrieve old messages from `firestore`, we’ll make a call to the database using the `useLayoutEffect`. Copy and paste the code below above the `onSend` function to load old messages on the chat screen:

```JSX
useLayoutEffect(() => {
        const unsubscribe = db.collection('chats').orderBy('createdAt', 'desc').onSnapshot(snapshot => setMessages(
            snapshot.docs.map(doc => ({
                _id: doc.data()._id,
                createdAt: doc.data().createdAt.toDate(),
                text: doc.data().text,
                user: doc.data().user,
            }))
        ));
```

## Conclusion

Now, you know how to build a standard chat application with cross-platform compatibility using React Native and Firebase. Our application allows us to chat between multiple devices with an unlimited number of users. 

react-native-gifted-chat is a great tool for implementing chat in React Native, helping you to improve communication within your application. You can read more about [react-native-gifted-chat](https://www.npmjs.com/package/react-native-gifted-chat) and [Firebase authentication](https://firebase.google.com/docs/auth/web/start) on the official docs.