The web was originally implemented on the principle of request and response: a client sends a request and a server replies with an appropriate response. When there is no requirement for data manipulation according to a client request, it's customary to serve a static page.

When dynamic pages came along, we were introduced to the concept of GET, POST, PUT, and DELETE requests. Now a client is able to ask for custom data from a server by sending its requirements as parameters. The server then processes the request and returns a dynamic response.

Still, the fundamentals are based on request and response: the client requests, the server responds, and the connection is closed.

There is another protocol that doesn't work like a request-response scheme known as WebSockets. In this tutorial, we'll introduce you to the WebSockets technology and some of its common use cases. We will walk you through how to implement WebSockets in React Native by designing a message broadcast app.

What are WebSockets?

WebSockets is a protocol that provides full-duplex communication, which means the client and server stay connected over a single TCP connection. Unlike request-response communication, the connection doesn't close here.

Since it's full-duplex, the server can also send data to the client without a request. This helps in saving bandwidth and response time.

The WebSockets protocol starts with ws://. For dealing with hypertext, we use http:// or https://.

Why use WebSockets?

There is a range of applications for WebSockets, but we primarily use them in cases where data needs to be either broadcasted or pushed by server.

For example, a chat app server needs to send a message to a recipient as soon as the sender sends it. The server can't wait for the client to request new messages, so it pushes them to the client using full-duplex communication. Similarly, news, trade matrix, and even social media posts are pushed in this way.

This outcome could be achieved before WebSockets entered the picture, but they were unreliable and inefficient.

For instance, many companies used long polling in which a browser sends a request but the server does not respond. The connection stays active until there is a connection timeout. In the meantime, if server has any message for the client, it responds and the connection closes. As soon as the connection closes, either due to timeout or server response, the client again sends the request. This process keeps going.

Another approach is to send an AJAX request in an interval of few seconds — say, three seconds — and get a server response, which is either a valid message or empty object. So, a new message can get delayed for, at most, three seconds. The downside of this approach is that a lot of API calls go to waste because the server doesn't have any message to respond to.

How to use WebSockets in React Native

There are four main functions that are executed during the lifecycle of WebSockets. They are called when the app establishes a connection, receives a messages, catches an error, and disconnects.

Let's zoom in on these functions.

Creating a WebSockets connection

The first step is to establish a connection with the server. WebSockets work on their own protocol, ws://.

In React Native, we can create a connection using the following code:

var ws = new WebSocket('ws://host.com/path'); 

Here the link corresponds to the socket service running on the backend.

If the server accepts the connection, it notifies the client by invoking the onopen function over the WebSocket object:

ws.onopen = () => {   // connection opened   ws.send('something');  // send a message }; 

This acts like the constructor. You can allocate resources in this function. Also, if you need to send some one-time information, such as a user identification number, to the server, you can do so here.

Receiving messages

In a request-response policy, the client looks for a response in the sent request. This means the client knows when it will get data from the server so it stays ready to handle it. But in full-duplex communication like WebSockets, the server can send data at any time without the consent of the client.

To handle this situation, a function must be invoked when the server sends a message.

In React Native, we have an onmessage function for this:

ws.onmessage = (e) => {   // a message was received   console.log(e.data); }; 

Handling errors

When there is an error, either due to poor internet connectivity or internal server errors, the onerror function is called:

ws.onerror = (e) => {   // an error occurred   console.log(e.message); }; 

Connection close

When the connection closes, either by the server or by the client, the onclose function is called. This acts like a destructor in that you can release the allocated resources.

ws.onclose = (e) => {   // connection closed   console.log(e.code, e.reason); }; 

Now we've seen the complete lifecycle of WebSockets in React Native, from establishing a connection to closing it. We can write all these functions in single block as follows:

var ws = new WebSocket('ws://host.com/path');  ws.onopen = () => {   // connection opened   ws.send('something'); // send a message };  ws.onmessage = (e) => {   // a message was received   console.log(e.data); };  ws.onerror = (e) => {   // an error occurred   console.log(e.message); };  ws.onclose = (e) => {   // connection closed   console.log(e.code, e.reason); }; 

WebSockets example: Message broadcasting app

To show WebSockets in action, let's create a simple message broadcasting app in Rect Native. In our demo app, a message sent from one application will be broadcast to all connected applications.

We'll develop the server script in Node.js. Here's the WebSockets server code:

const express = require("express"); const app = express(); const http = require("http"); const WebSocket = require("ws"); const server = http.createServer(app); const wss = new WebSocket.Server({ server }); wss.on("connection", function connection(ws) {   ws.on("message", function incoming(message, isBinary) {     console.log(message.toString(), isBinary);     wss.clients.forEach(function each(client) {       if (client.readyState === WebSocket.OPEN) {         client.send(message.toString());       }     });   }); }); app.get("/", (req, res) => {   res.send("Hello World!"); }); server.listen(8080, () => {   console.log("Listening to port 8080"); }); 

You can find this code in the npm repositoriy for the ws package.

Remember, you need to keep the server active. Otherwise, clients won't be able to connect.

See an interactive demo on CodeSandbox.

Client code

Now that our server is running successfully, it's time to create our React Native app.

At the top, we'll create a horizontal bar to show connection or disconnection notifications as well as errors. At the bottom, we'll place an input field and a submit button to send messages through WebSockets. The rest of the middle area will be used to display the list of messages received from the server.

It's a broadcast app, so any message sent from any device will be broadcasted to all.

Let's check out the code:

import * as React from 'react'; import { Text, View, StyleSheet, TextInput, Button, ScrollView } from 'react-native';   export default function App() {   const [serverState, setServerState] = React.useState('Loading...');   const [messageText, setMessageText] = React.useState('');   const [disableButton, setDisableButton] = React.useState(true);   const [inputFieldEmpty, setInputFieldEmpty] = React.useState(true);   const [serverMessages, setServerMessages] = React.useState([]);   var ws = React.useRef(new WebSocket('ws://w567l.sse.codesandbox.io/')).current;     React.useEffect(() => {     const serverMessagesList = [];     ws.onopen = () => {       setServerState('Connected to the server')       setDisableButton(false);     };     ws.onclose = (e) => {       setServerState('Disconnected. Check internet or server.')       setDisableButton(true);     };     ws.onerror = (e) => {       setServerState(e.message);     };     ws.onmessage = (e) => {       serverMessagesList.push(e.data);       setServerMessages([...serverMessagesList])     };   }, [])   const submitMessage = () => {     ws.send(messageText);     setMessageText('')     setInputFieldEmpty(true)   }   return (     <View style={styles.container}>       <View style={{         height: 30,         backgroundColor: '#eeceff',         padding: 5       }}>         <Text>{serverState}</Text>       </View>       <View style={{         backgroundColor: '#ffeece',         padding: 5,         flexGrow: 1       }}>         <ScrollView>           {             serverMessages.map((item, ind) => {               return (                 <Text key={ind}>{item}</Text>               )             })           }         </ScrollView>       </View>       <View style={{         flexDirection: 'row',       }}>         <TextInput style={{             borderWidth: 1,             borderColor: 'black',             flexGrow: 1,             padding: 5,           }}            placeholder={'Add Message'}            onChangeText={text => {             setMessageText(text)             setInputFieldEmpty(text.length > 0 ? false : true)             }}           value={messageText}          />         <Button          onPress={submitMessage}          title={'Submit'}           disabled={disableButton || inputFieldEmpty}         />       </View>      </View>   ); } const styles = StyleSheet.create({   container: {     flex: 1,     backgroundColor: '#ecf0f1',     paddingTop: 30,     padding: 8,   },  }); 

To summarize in brief, the process for implementing WebSockets in a React Native app is as follows:

  1. The React Native app create a new WebSockets connection and store it in a reference variable, ws
  2. The top bar of the app shows the value of the serverState variable, the middle part displays a text messages stored in the serverMessages array, and the bottom bar has an input field that stores typed messages in the messageText state variable
  3. The submit button only becomes active when the app is connected to WebSockets successfully and there is some text in the input box. We control it using the disableButton and inputFieldEmpty variables. The submit button will be active when both disableButton and inputFieldEmpty are false
  4. In the useEffect() hook, we define all the WebSocket functions
  5. When the WebSockets connection is opened by the server, the onopen function is called. This changes the value of serverState variable to connected to the server and disableButton to false, so the top bar of the app shows the connected message
  6. When the connection closes, the onclose function is called. This changes the serverState to disconnected message and disableButton to true. At this point, the submit button is no longer active, even if you type a message in the input box, because we can't send messages to the server
  7. If there is an error, the onerror function is called and changes the serverState to that particular error message
  8. When the server broadcasts messages, the onmessage function is called. This will append the received message into the serverMessages array
  9. We created a submitMessage message to send the message to the server, which the server broadcasts to all devices

Here, I embedded two instances of this app: one for Android and another for iOS. You can test that the message sent from one device will be shown on both. Verify that the Node.js server we embedded above is running fine and is not in hibernation mode.

If you encounter problems with the above devices, you can run the code here.

Conclusion

In this tutorial, we showed you how easy it is to create WebSockets in a React Native apps. The code will run on both Android and iOS platforms.

We created a simple broadcast app for this particular demonstration, but there is a lot of scope to expand it. For example, you could set IDs to distinguish between clients and align messages sent by the client to the right side and all others to the left side. This will produce a perfect chat app-like look and feel.

You could also create a form to capture details (such as the user's name) before starting a chat and show the information beside received messages.

Let us know in comments what kinds of things you've built in React Native using WebSockets.