Skip to content

React Native

WebMQ works in React Native (including Expo) out of the box — the library self-polyfills EventTarget, CustomEvent, TextEncoder, TextDecoder and hooks into AppState for reconnect-on-foreground automatically. The mobile-chat example shows a complete Expo app interoperating with the web basic-chat on the same exchange.

Usage is identical to React:

import { useEffect, useState } from 'react';
import { View, Text, TextInput, Button, FlatList } from 'react-native';
import WebMQClient from 'webmq-frontend';

const client = new WebMQClient({
  url: 'ws://localhost:8080',
  sessionId: 'user-session'
});

export default function App() {
  const [messages, setMessages] = useState([]);
  const [input, setInput] = useState('');

  useEffect(() => {
    client.connect();
    client.listen('chat.messages', (msg) =>
      setMessages((prev) => [...prev, msg]));
    return () => { client.unlisten('chat.messages'); client.disconnect(); };
  }, []);

  const send = () => {
    client.publish('chat.messages', { text: input, user: 'mobile-user' });
    setInput('');
  };

  return (
    <View>
      <FlatList data={messages} renderItem={({ item }) =>
        <Text><Text style={{fontWeight:'bold'}}>{item.user}:</Text> {item.text}</Text>
      } keyExtractor={(_, i) => i} />
      <TextInput value={input} onChangeText={setInput} placeholder="Type..." />
      <Button title="Send" onPress={send} />
    </View>
  );
}

NetInfo for faster reconnect

The library detects app-foreground via AppState, but that doesn't mean the network is back. For network-aware reconnection, wire up @react-native-community/netinfo (or expo-network) to call client.forceReconnect():

import NetInfo from '@react-native-community/netinfo';

useEffect(() => {
  const unsubscribe = NetInfo.addEventListener((state) => {
    if (state.isConnected && state.isInternetReachable !== false) {
      client.forceReconnect();
    }
  });
  return () => unsubscribe();
}, []);

Connection-aware UI

function ConnectionDot({ client }) {
  const [color, setColor] = useState('orange');
  useEffect(() => {
    if (!client) return;
    const on = (e) => setColor({ connected: 'green', disconnected: 'red', reconnecting: 'orange' }[e.type]);
    client.addEventListener('connected', on);
    client.addEventListener('disconnected', on);
    client.addEventListener('reconnecting', on);
    return () => {
      client.removeEventListener('connected', on);
      client.removeEventListener('disconnected', on);
      client.removeEventListener('reconnecting', on);
    };
  }, [client]);
  return <View style={{ width: 12, height: 12, borderRadius: 6, backgroundColor: color }} />;
}

Expo monorepo setup

When using Expo in a monorepo, configure metro.config.js to watch the workspace root:

const { getDefaultConfig } = require('expo/metro-config');
const path = require('path');

const config = getDefaultConfig(__dirname);
config.watchFolders = [path.resolve(__dirname, '..')];
config.resolver.nodeModulesPaths = [
  path.resolve(__dirname, 'node_modules'),
  path.resolve(__dirname, '../node_modules')
];

module.exports = config;