React Native provides a WebSocket implementation that follows the Web API specification. WebSockets enable bidirectional, real-time communication between a client and server.
Constructor
new WebSocket(url: string, protocols?: string | string[], options?: object)
Creates a new WebSocket connection.
The URL to connect to. Must use ws:// or wss:// protocol.
Optional subprotocol(s) to use. Can be a single string or array of strings.
Connection optionsCustom headers to include in the connection request
Properties
State Constants
Connection is being established
Connection is open and ready to communicate
Connection is in the process of closing
Instance Properties
Current connection state. One of the state constants above.
The URL of the WebSocket connection
The subprotocol selected by the server
Number of bytes queued to be sent
Type of binary data received. Can be set to 'blob' or 'arraybuffer'.
Methods
send()
send(data: string | ArrayBuffer | ArrayBufferView | Blob): void
Sends data through the WebSocket connection.
data
string | ArrayBuffer | ArrayBufferView | Blob
required
Data to send:
- string: Text message
- ArrayBuffer: Binary data
- ArrayBufferView: Typed array (Uint8Array, etc.)
- Blob: Binary large object
Throws INVALID_STATE_ERR if called before connection is open.
close()
close(code?: number, reason?: string): void
Closes the WebSocket connection.
Close status code. Default is 1000 (normal closure).Common codes:
1000 - Normal closure
1001 - Going away
1002 - Protocol error
1003 - Unsupported data
1006 - Abnormal closure (no close frame received)
Human-readable reason for closing
ping()
Sends a ping frame to the server. Used for keep-alive.
Throws INVALID_STATE_ERR if called before connection is open.
Event Handlers
onopen
ws.onopen = (event) => {
// Connection opened
};
Called when the WebSocket connection is successfully opened.
onmessage
ws.onmessage = (event) => {
// event.data contains the message
};
Called when a message is received from the server.
The event.data can be:
string for text messages
ArrayBuffer if binaryType is set to 'arraybuffer'
Blob if binaryType is set to 'blob'
onerror
ws.onerror = (event) => {
// Connection error occurred
};
Called when an error occurs.
onclose
ws.onclose = (event) => {
// event.code contains the close code
// event.reason contains the close reason
};
Called when the connection is closed.
The event object contains:
code - Close status code
reason - Close reason string
Examples
Basic Connection
const ws = new WebSocket('wss://echo.websocket.org');
ws.onopen = () => {
console.log('Connected');
ws.send('Hello Server!');
};
ws.onmessage = (e) => {
console.log('Received:', e.data);
};
ws.onerror = (e) => {
console.error('Error:', e.message);
};
ws.onclose = (e) => {
console.log('Closed:', e.code, e.reason);
};
React Component
import React, {useEffect, useState} from 'react';
import {View, Text, Button, TextInput} from 'react-native';
function WebSocketChat() {
const [ws, setWs] = useState(null);
const [message, setMessage] = useState('');
const [messages, setMessages] = useState([]);
const [connected, setConnected] = useState(false);
useEffect(() => {
const websocket = new WebSocket('wss://echo.websocket.org');
websocket.onopen = () => {
console.log('Connected');
setConnected(true);
};
websocket.onmessage = (e) => {
setMessages(prev => [...prev, `Server: ${e.data}`]);
};
websocket.onerror = (e) => {
console.error('WebSocket error:', e.message);
};
websocket.onclose = (e) => {
console.log('Disconnected:', e.code, e.reason);
setConnected(false);
};
setWs(websocket);
return () => {
websocket.close();
};
}, []);
const sendMessage = () => {
if (ws && message) {
ws.send(message);
setMessages(prev => [...prev, `You: ${message}`]);
setMessage('');
}
};
return (
<View>
<Text>Status: {connected ? 'Connected' : 'Disconnected'}</Text>
{messages.map((msg, i) => (
<Text key={i}>{msg}</Text>
))}
<TextInput
value={message}
onChangeText={setMessage}
placeholder="Type a message"
/>
<Button
title="Send"
onPress={sendMessage}
disabled={!connected}
/>
</View>
);
}
const ws = new WebSocket(
'wss://api.example.com/socket',
null,
{
headers: {
Authorization: 'Bearer your-token-here',
'X-Custom-Header': 'value',
},
}
);
Binary Data with ArrayBuffer
const ws = new WebSocket('wss://example.com/binary');
ws.binaryType = 'arraybuffer';
ws.onopen = () => {
// Send binary data
const buffer = new ArrayBuffer(4);
const view = new Uint8Array(buffer);
view[0] = 1;
view[1] = 2;
view[2] = 3;
view[3] = 4;
ws.send(buffer);
};
ws.onmessage = (e) => {
if (e.data instanceof ArrayBuffer) {
const view = new Uint8Array(e.data);
console.log('Received binary:', view);
}
};
Binary Data with Blob
const ws = new WebSocket('wss://example.com/blob');
ws.binaryType = 'blob';
ws.onmessage = async (e) => {
if (e.data instanceof Blob) {
const text = await e.data.text();
console.log('Blob as text:', text);
}
};
Automatic Reconnection
import React, {useEffect, useRef, useState} from 'react';
function useWebSocket(url, options = {}) {
const [readyState, setReadyState] = useState(WebSocket.CONNECTING);
const ws = useRef(null);
const reconnectTimeout = useRef(null);
const connect = () => {
ws.current = new WebSocket(url);
ws.current.onopen = () => {
console.log('Connected');
setReadyState(WebSocket.OPEN);
if (options.onOpen) options.onOpen();
};
ws.current.onmessage = (e) => {
if (options.onMessage) options.onMessage(e);
};
ws.current.onerror = (e) => {
console.error('Error:', e.message);
if (options.onError) options.onError(e);
};
ws.current.onclose = (e) => {
console.log('Closed:', e.code, e.reason);
setReadyState(WebSocket.CLOSED);
if (options.onClose) options.onClose(e);
// Attempt to reconnect after 3 seconds
reconnectTimeout.current = setTimeout(() => {
console.log('Reconnecting...');
connect();
}, 3000);
};
};
useEffect(() => {
connect();
return () => {
if (reconnectTimeout.current) {
clearTimeout(reconnectTimeout.current);
}
if (ws.current) {
ws.current.close();
}
};
}, [url]);
const send = (data) => {
if (ws.current && readyState === WebSocket.OPEN) {
ws.current.send(data);
} else {
console.warn('WebSocket not connected');
}
};
return {readyState, send};
}
// Usage
function MyComponent() {
const {readyState, send} = useWebSocket('wss://echo.websocket.org', {
onMessage: (e) => console.log('Message:', e.data),
});
return (
<Button
title="Send"
onPress={() => send('Hello!')}
disabled={readyState !== WebSocket.OPEN}
/>
);
}
Ping/Keep-Alive
const ws = new WebSocket('wss://example.com');
let pingInterval;
ws.onopen = () => {
// Send ping every 30 seconds
pingInterval = setInterval(() => {
if (ws.readyState === WebSocket.OPEN) {
ws.ping();
}
}, 30000);
};
ws.onclose = () => {
clearInterval(pingInterval);
};
JSON Messages
const ws = new WebSocket('wss://api.example.com');
ws.onopen = () => {
// Send JSON data
const data = {
type: 'subscribe',
channel: 'updates',
};
ws.send(JSON.stringify(data));
};
ws.onmessage = (e) => {
try {
const data = JSON.parse(e.data);
console.log('Parsed message:', data);
} catch (error) {
console.error('Failed to parse JSON:', error);
}
};
Notes
- WebSocket follows the browser WebSocket API specification
- Secure connections (
wss://) are recommended for production
- On iOS, configure App Transport Security to allow non-HTTPS connections if needed
- Binary data requires setting
binaryType property
- Use
ping() for keep-alive on long-lived connections
- Always clean up WebSocket connections in component unmount
- Consider using libraries like
socket.io-client for advanced features (rooms, automatic reconnection, etc.)
- Handle reconnection logic for production applications
- Be mindful of battery usage with persistent connections