By Walter Rodriguez
Solutions Engineer | Sendbird
The post How to build a chat app using React Native and Hooks appeared first on Sendbird.
Introduction
This tutorial will show you how to build a messaging app using React Native. First, we’ll set the stage for this tutorial by understanding why you should use React Native in the first place. Then we’ll explain React Native Hooks functions before diving into the implementation details of how to build a chat application with Sendbird and React Native.
Please note that this tutorial assumes a basic understanding of React Native.
With this in mind, let’s begin.
Why React Native?
Most applications today are built natively, but there are also hybrid applications developed using Webviews. The properties and features of Webviews introduce limits to applications in comparison to their native counterparts, however. Applications using Webviews are also relatively slower than native applications. React Native allows to bridge this gap by providing applications access to native functionality and properties.
React Native does this by separating the JavaScript code and native code into different threads. It also enables asynchronous communication between the two, which boosts the overall app performance. Moreover, since React Native uses JavaScript, developers unfamiliar with native applications can use their existing knowledge and experience to reduce coding time.
Who is using React Native?
Because of its advantages of code reusability, reliability, robustness, and the existence of a helpful community, many companies, from established Fortune 500 companies to high-growth startups, develop applications with React Native. Some well-regarded organizations using React Native include Instagram, Shopify, Tableau, Tesla, UberEats, and Skype.
Now that we have understood the basics let’s move on to React Native Hooks functions.
What are React Native Hooks functions?
Hooks are functions that let you “hook” into React states and lifecycle features from function components. Hooks don’t work inside classes — they let you use React without classes. (We don’t recommend rewriting your existing components overnight, but you can start using Hooks in the new ones if you’d like.)
React provides a few built-in Hooks such as useState. You can also create your own Hooks to reuse stateful behavior between different components. Let’s look at the built-in Hooks first.
For more information about Hooks, check out the react site.
Now let’s understand how to work with Sendbird and Hooks for your chat application. This tutorial is composed of nine more parts:
- Installing React Native
- Downloading the Sendbird sample
- Debugging
- Understanding the folder structure
- Building the Login component
- Building the Channels List component
- Building the Messages component
- Sending and receiving messages
- Other Sendbird features
Step 1. Installing React Native to build chat
You need to have the React Native CLI to work with this example. Please install globally:
npm install -g react-native-cli
You can quickly check that the installation finished correctly by showing the version number:
react-native --version
Step 2. Downloading the Sendbird sample
Once you have the React Native CLI installed, you can download the sample code. First clone the repository:
git clone https://github.com/sendbird/SendBird-JavaScript.git
Then, open the following folder using your favorite IDE:
./SendBird-JavaScript/react-native-hook-sample/Sendbird
As the next step, let’s install all the dependencies. Run the following command: (it takes some time to download all packages)
npm i
You can run this either for Android or iOS. Open the package.json file and check the scripts we have for you to use:
To run Android, just type:
npm run android
Troubleshooting Android
If you have problems running the Android version, you can try the following:
- If you run on an actual device, check if everything is installed – especially Android studio.
- Check if your device is visible by adb devices; sometimes, it may not work or have lags. In this case, call adb kill-server and then adb start-server.
- You might want to build the project using react-native run-android. If it fails, you might need to run it with Android studio.
- Make sure your ANDROID_HOME is in the path. Something like:
export ANDROID_HOME=/Users/[your user]/Library/Android/sdk
For iOS, you need to install Pods once:
cd ios
pod install
pod update
This will install all the libraries to run the iOS version.
Troubleshooting iOS
If you have problems running the iOS version, you can try the following:
- Do a pod update and then pod install from inside the ios/ folder.
- Delete the ios/build folder.
- It is better not to change any build phases, rules, or settings in XCode as this may cause further issues.
- It is better not to update the packages listed in the package.json file or the ones inside ios/Pods. This is because these are the versions used in our testing.
Troubleshooting for both platforms
- Make sure you are not running any VPN. Sometimes this creates problems.
- If you have a React Native terminal window running, try closing it and run the command above again.
- You can run npm run clean from the root directory. This will clean old builds.
- You can delete the file package-lock.json, and try running npm i again, but we do not recommend this because of compatibility issues.
Check the list of prerequisites before running this sample. You can find them here.
Step 3. Debugging your React Native chat app
From your iOS simulator, you can debug the application and see console outputs to Chrome. Press Command + D to see a screen like below:
When you click Debug in Chrome, a Chrome window will open. Use the Chrome developer tools to monitor the outputs written by console.log().
Step 4. Understanding the folder structure
The following is a description of the most important files and folders for this sample application.
package.json
This file contains all the packages this project will use. Because of compatibility issues, we recommend not changing the version of these packages.
The file also contains the scripts you can run:
Run npm run android to launch the Android version.
Run npm run ios to launch the iOS version.
Run npm run clean to clear any previous build.
node_modules
This folder contains all the downloaded libraries this project will use. This folder is created every time you run npm i.
android
This folder contains all the files for an Android project. You can use Visual Studio to open and run the project.
iOS
This folder contains all the files for the iOS project. You can open it with Xcode.
src
This folder contains all the Javascript files for our demo application.
index.js
This is the first file to be executed by React Native.
We define which function will process the information when we receive a Push message, for Android devices. In this example, the function onRemoteMessage will do the work. It is inside the ./src/utils utils.js file.
App.js
This file is called from the file index.js. It shows the first screen we see when users run our application.
You will see where your Sendbird application ID (you can get this from your Sendbird Dashboard) is defined:
We are now ready to initialize the Sendbird SDK. At this point, we are not connected.
We will use our first Hook to ask permission to receive notifications.
If we already have a token from Firebase, we use the Sendbird function registerAPNSPushtokenForCurrentUser to register it for an iOS device and registerGCMPushTokenForCurrentUser for an Android device.
View a detailed tutorial about implementing Firebase for React Native.
The next step is to define our Stack Navigator. A Stack Navigator provides a way for your app to transition between screens. Each new screen can be placed on top of a stack.
By default, the stack navigator offers a familiar iOS and Android look and feel. New screens slide in from the right on iOS, and the default OS animation is used on Android. You can customize the animations to match your needs.
Step 5. Building the Login component for your React Native chat app
The Stack Navigator will Lobby first. This file is in ./src/page/lobby.js.
Many Hooks are applied here, and the principal actor is currentUser. Because it depends on the user previously signed, we will show a login screen or the list of chat channels.
This sample uses AsyncStorage to read (and save) the value of a previously signed user. If there’s a value, we read it and define that the user as initialized.
We build the screen accordingly. If we have a signed user, we show the Channels component. Otherwise, we show the Login screen.
Once the Login component responds, the login function executes. We save this value in the AsyncStorage and run the token registration for iOS and/or Android to receive push notifications.
The login screen will paint the screen we see above and wait for the user to click on the Connect button.
When clicked, the button calls the connect function connect.
Connecting to Sendbird
As you can see, the sendbird.connect(…) function call connects the device with the Sendbird servers via Websockets. If you see any error here, it is because the user ID selected is invalid, your Sendbird application ID is incorrect, the function is not defined, or because you’re not connected to the Internet.
We suggest you check for any error code and inform your users.
Foreground and background
You must check if your application goes to the background, for the following screens (channels, messages, etc.). If this happens, then you should invoke setBackgroundState. You will appear as disconnected for the rest of the users. Call setForegroundState once the application returns to the front. This will make Websockets connect again and the logged user appear online again.
After a successful connection, we store this user’s nickname (from the input screen) and return it to the Lobby component. Once the user is set, the Channels screen appears.
Step 6. Building the Channels List component
Sendbird works with public Open Channels and Group Channels. You don’t need an invitation, any user can enter a message, for the Open Channels. Group Channels are the opposite. You need an invitation to join the channel and send messages.
To learn more about channel types, see this page or this tutorial.
Now, open the ./src/page/channels.js file and see all the essential parts that should be there.
- Add a connection handler to receive Websocket disconnections notifications.
Customers must know when the SDK is not connected because your application should stop all requests until a connection is made. Otherwise, your users will think that your application is not working.
- Add a channel handler to receive updates from Sendbird about any events. You will be able to react to channel modifications, new messages, users being added or removed from channels, etc.
A channel handler helps your application to update visually and inform the customer about any changes made by other users.
Also, remember to remove your handlers when destroying each view.
Read more about connection and channel handlers here.
Listing your channels
When listing channels, the maximum number of records you can receive from the server is 100. If you need more, you must use next(…) to call the server again:
Once the user selects a channel, our application will navigate to the chat, passing the selected channel and current signed user.
This leads us to the messages screen.
Step 7. Building the Messages components
After selecting a channel, the application will show you a list of messages for this channel only:
The code for this screen is in ./src/page/chat.js.
Naturally, the list of messages is the most important part of this screen. But let’s take a look at other parts that must be included:
A connection handler to manage disconnections and stop customers from sending messages.
A channel handler to receive any changes related to the channels (including messages added, removed, etc.), via Websockets.
You need to remove these handlers when this view is no longer active for users.
In this sample application, we will take action for the following events:
onMessageReceived: A new message is received via Websocket. Add this new message to the list of messages only if the channel URL informed from the event is the same channel you have active in this view.
onMessageUpdated: A message has been updated. If this informed message belongs to this active channel, you must update its content from the list.
onMessageDeleted: A message has been deleted. If this informed message belongs to this active channel, you must remove it from the list.
You can also receive events about to this user and the channel. For example:
onUserLeft: If a user left the channel, you should check if the signed user ID matches the informed user ID. If both are the same, it means that you decided to leave the channel from another device. Your action should be something like going back to the main list of channels (channels.js).
onChannelDeleted: Another critical check is the existence of the channel that contains the messages you are showing. If this channel is missing for any reason, you should also return to the main screen with the list of remaining channels (channels.js).
Mark channel as read
When you enter to see the messages in a channel, you should mark all messages as read.
Listing your messages
We will ask Sendbird for the list of messages in this active channel. To do this, we use createPreviousMessageListQuery
To view more information, see this page. You can also check out this tutorial about messaging objects.
For this example, we list the last 50 messages. If more messages are available to show, you should call next() to get more data.
Getting messages according to the timestamp
You also can request a list of messages according to a specific timestamp. Use something like new Date().getTime() and define how many previous messages you want to show.
This technique will help you load previous messages if the user scrolls up to get a long history of messages. You just need to keep sending the message’s timestamp and ask for previous records to show until you reach the first message sent to the channel.
To find more information, check our docs.
Step 8. Sending and receiving messages
With Sendbird, you can send a text or a file message.
Note that a message for Sendbird is not just a text or a file; we have other attributes to send confidential information to your server or to the other connected users.
Custom type
This attribute is part of the message object, and it specifies a custom message type for message grouping. The length is limited to 128 characters.
The Sendbird Advanced Analytics also uses Custom types to segment metrics. They enable the sub-classification of data views.
Data
Data is another attribute you can use for your internal logic. It specifies additional message information such as custom font size, font type, or any data you want to handle with a JSON formatted string.
To find a list of attributes for a message, click here.
To get more information about sending a message via the SDK and Javascript, see this page.
Below is the code to send a message.
File messages
With Sendbird, you can also send file messages. In this application, we allow users to select the file from the device and then send it.
Remember to request permission.
When working with Android and iOS, you must request permission from users before using a file picker.
Important: Sendbird requires a Javascript File object as the file to upload. You may receive errors or have a failed upload if trying to send another format. Sometimes, the custom file pickers used from public repositories don’t deliver the proper object type.
Remember that when sending file messages, you cannot send text along with it. However, you can use other message object attributes to send a text and display it on the chat list. Check out the list of available attributes for a file message:
More information is in the docs.
Thumbnails for image files
When uploading image files, you can ask Sendbird to generate a thumbnail automatically. Enable this from your dashboard:
Voice messages
You can send voice messages with file messages. Your frontend application should implement a voice recording function and save the result as a file. Then you just upload that file, along with any of the custom attributes we provide for the message object, indicating that this is a voice message file. When drawing this message in the channel, analyze the information and show it properly.
Reply to messages
Sendbird supports message threading so you can respond to messages.
To do this, you must indicate the parent message ID when sending a response.
You can respond with a text message:
Or with a file message:
To learn more about messages, check out the docs and this tutorial.
Step 9. Other Sendbird features
Sendbird offers a variety of features for your chat experience.
Typing indicators
In this example, you can see the use of startTyping() and endTyping() to send events to all members in the channel.
This event triggers the onTypingStatusUpdated function from the channel handler.
The rest is to show a label saying that user XXX is typing a message.
Moderation
Sendbird provides powerful tools for moderation. You can use the Sendbird Dashboard to moderate messages and users. You may also register or unregister channel members as Operators so that they can freeze channels, block, or mute users.
To review all the features that Sendbird offers, check out our JavaScript docs and this tutorial for moderation best practices.
Conclusion
So that’s a wrap! Many more features are available in the JavaScript SDK, so make sure to check out the documentation to build an even more advanced messaging app.
This tutorial gave you a taste for building a React Native chat app with the Sendbird JavaScript SDK. To learn more about React Native, refer to the official documentation.
If you have any questions regarding this tutorial or using Sendbird in general, please drop us a note on our community page.
Thanks, and happy React Native chat building!
Top comments (0)