Skip to main content
Version: 0.25.0

Text Chat

This guide shows how to implement text chat in your application using data channels. Data channels allow you to send and receive arbitrary binary data between peers in a room.

Prerequisites

Before implementing text chat, you must be connected to a room. Data channels only work after you have successfully joined a room.

tip

For a deeper understanding of how data channels work, including channel types and broadcast behavior, see Data Channels.


Step 1 — Set up the chat hook

Use the useDataChannel hook to work with data channels. The typical flow is:

  1. Initialize the data channel after connecting to a room
  2. Subscribe to incoming messages
  3. Publish messages to other peers
import { useConnection, useDataChannel } from "@fishjam-cloud/react-client"; import { useCallback, useEffect, useState } from "react"; export function useChat() { const { peerStatus } = useConnection(); const { initializeDataChannel, publishData, subscribeData, dataChannelReady, } = useDataChannel(); const [messages, setMessages] = useState<string[]>([]); // Step 1: Initialize data channel when connected useEffect(() => { if (peerStatus === "connected") { initializeDataChannel(); } }, [peerStatus, initializeDataChannel]); // Step 2: Subscribe to incoming messages useEffect(() => { if (!dataChannelReady) return; const unsubscribe = subscribeData( (data: Uint8Array) => { const message = new TextDecoder().decode(data); setMessages((prev) => [...prev, message]); }, { reliable: true }, ); return unsubscribe; }, [subscribeData, dataChannelReady]); // Step 3: Publish messages const sendMessage = useCallback( (text: string) => { if (!dataChannelReady) return; const encoded = new TextEncoder().encode(text); publishData(encoded, { reliable: true }); }, [publishData, dataChannelReady], ); return { messages, sendMessage, ready: dataChannelReady }; }

Step 2 — Use the chat hook in your component

Once you have the hook, you can use it in any component to send and display messages:

function ChatPanel() { const { messages, sendMessage, ready } = useChat(); const [input, setInput] = useState(""); const handleSend = () => { if (input.trim()) { sendMessage(input); setInput(""); } }; if (!ready) { return <div>Connecting to chat...</div>; } return ( <div> <div> {messages.map((msg: string, i: number) => ( <div key={i}>{msg}</div> ))} </div> <input value={input} onChange={(e) => setInput(e.target.value)} onKeyDown={(e) => e.key === "Enter" && handleSend()} /> <button onClick={handleSend}>Send</button> </div> ); }

Why use the reliable channel?

For chat messages, we use { reliable: true } because:

  • Ordered delivery: Messages arrive in the order they were sent
  • Guaranteed delivery: All messages will be delivered, with automatic retransmission if needed

This ensures no chat messages are lost or arrive out of order.


See also