Skip to content

Navigation Menu

Sign in
Sign up

Framework Hooks React Vue Svelte

jfarcand edited this page Feb 18, 2026 · 3 revisions

Framework Hooks — React, Vue, and Svelte

atmosphere.js 5.0 ships first-class hooks for React, Vue, and Svelte that manage the full Atmosphere lifecycle — connection, reconnection, cleanup on unmount, and reactive state. No boilerplate WebSocket plumbing needed.

Installation

npm install atmosphere.js

The hooks are tree-shakeable sub-paths — only the framework you import gets bundled:

import { ... } from 'atmosphere.js/react'; // React 18+
import { ... } from 'atmosphere.js/vue'; // Vue 3
import { ... } from 'atmosphere.js/svelte'; // Svelte 4/5

React

AtmosphereProvider

All React hooks require an AtmosphereProvider ancestor that holds the shared Atmosphere client instance:

import { AtmosphereProvider } from 'atmosphere.js/react';
function App() {
 return (
 <AtmosphereProvider config={{ logLevel: 'info' }}>
 <Chat />
 </AtmosphereProvider>
 );
}

You can also pass a pre-built instance:

<AtmosphereProvider instance={myAtmosphere}>

useAtmosphere

Low-level hook for a raw Atmosphere subscription. Connects on mount, disconnects on unmount, re-connects when URL or transport changes.

import { useAtmosphere } from 'atmosphere.js/react';
function Notifications() {
 const { data, state, push, error } = useAtmosphere<Notification>({
 request: { url: '/atmosphere/notifications', transport: 'websocket' },
 });
 if (state === 'connected' && data) {
 return <div>{data.text}</div>;
 }
 return <div>Connecting...</div>;
}

Return type:

Field Type Description
subscription Subscription | null The active subscription (null before connected)
state ConnectionState 'disconnected' · 'connected' · 'reconnecting' · 'closed' · 'error'
data T | null Last received message (generic)
error Error | null Last error
push (msg) => void Send a message (string, object, or ArrayBuffer)

Options:

Field Type Default Description
request AtmosphereRequest (required) Connection config (url, transport, etc.)
enabled boolean true Set to false to defer connection

useRoom

Joins a room and tracks members, messages, and presence — reactive state updates on every event:

import { useRoom } from 'atmosphere.js/react';
interface ChatMessage {
 text: string;
}
function Chat() {
 const { joined, members, messages, broadcast, sendTo, error } = useRoom<ChatMessage>({
 request: { url: '/atmosphere/room', transport: 'websocket' },
 room: 'lobby',
 member: { id: 'alice', metadata: { name: 'Alice' } },
 });
 return (
 <div>
 <p>{joined ? `Online: ${members.length}` : 'Joining...'}</p>
 <ul>
 {messages.map((m, i) => (
 <li key={i}><b>{m.member.id}</b>: {m.data.text}</li>
 ))}
 </ul>
 <button onClick={() => broadcast({ text: 'Hello!' })}>Send</button>
 </div>
 );
}

Return type:

Field Type Description
joined boolean Whether the room has been joined
members RoomMember[] Current room members
messages Array<{ data: T; member: RoomMember }> Messages received (append-only)
broadcast (data: T) => void Broadcast to all room members
sendTo (memberId: string, data: T) => void Direct message to one member
error Error | null Last error

usePresence

Convenience wrapper around useRoom that exposes only presence state — no messages:

import { usePresence } from 'atmosphere.js/react';
function OnlineIndicator() {
 const { members, count, isOnline } = usePresence({
 request: { url: '/atmosphere/room', transport: 'websocket' },
 room: 'lobby',
 member: { id: currentUser.id },
 });
 return (
 <div>
 <span>{count} online</span>
 {isOnline('bob') && <span>Bob is here!</span>}
 </div>
 );
}

Return type:

Field Type Description
joined boolean Whether we have joined the room
members RoomMember[] Current online members
count number Number of members online
isOnline (memberId: string) => boolean Check if a specific member is online

Vue

Vue composables work without a provider — pass an Atmosphere instance or let each composable create one.

useAtmosphere

<script setup lang="ts">
import { useAtmosphere } from 'atmosphere.js/vue';

const { data, state, push } = useAtmosphere<ChatMessage>({
 url: '/atmosphere/chat',
 transport: 'websocket',
});
</script>
<template>
 <div>State: {{ state }}</div>
 <div v-if="data">{{ data }}</div>
 <button @click="push(JSON.stringify({ text: 'Hello' }))">Send</button>
</template>

Returns the same fields as the React hook, but as Vue Ref values (reactive).

useRoom

<script setup lang="ts">
import { useRoom } from 'atmosphere.js/vue';

const { joined, members, messages, broadcast, sendTo } = useRoom<ChatMessage>(
 { url: '/atmosphere/room', transport: 'websocket' },
 'lobby',
 { id: 'alice' },
);
</script>
<template>
 <div v-if="joined">
 <p>{{ members.length }} members online</p>
 <div v-for="msg in messages" :key="msg.data.text">
 <b>{{ msg.member.id }}</b>: {{ msg.data.text }}
 </div>
 <button @click="broadcast({ text: 'Hello!' })">Send</button>
 </div>
 <div v-else>Joining room...</div>
</template>

Signature: useRoom<T>(request, roomName, member, instance?)

All returned values (joined, members, messages, error) are Vue Ref objects — they update reactively in templates and watchers.

usePresence

<script setup lang="ts">
import { usePresence } from 'atmosphere.js/vue';

const { members, count, isOnline } = usePresence(
 { url: '/atmosphere/room', transport: 'websocket' },
 'lobby',
 { id: currentUser.id },
);
</script>
<template>
 <span>{{ count }} online</span>
</template>

count is a Vue computed ref — automatically recalculated when members change.


Svelte

Svelte hooks use the Svelte store contract (subscribe method). Use $store auto-subscription syntax.

createAtmosphereStore

<script>
 import { createAtmosphereStore } from 'atmosphere.js/svelte';

 const { store: chat, push } = createAtmosphereStore({
 url: '/atmosphere/chat',
 transport: 'websocket',
 });
 // $chat.state, $chat.data, $chat.error
</script>
<p>State: {$chat.state}</p>
{#if $chat.data}
 <p>{JSON.stringify($chat.data)}</p>
{/if}
<button on:click={() => push(JSON.stringify({ text: 'Hello' }))}>Send</button>

Store state:

Field Type Description
state ConnectionState Connection state
data T | null Last received message
error Error | null Last error
subscription Subscription | null Active subscription

The store auto-connects when the first subscriber appears and disconnects when all subscribers are gone.

createRoomStore

<script>
 import { createRoomStore } from 'atmosphere.js/svelte';

 const { store: lobby, broadcast, sendTo } = createRoomStore(
 { url: '/atmosphere/room', transport: 'websocket' },
 'lobby',
 { id: 'alice' },
 );
</script>
{#if $lobby.joined}
 <p>{$lobby.members.length} members online</p>
 {#each $lobby.messages as msg}
 <p><b>{msg.member.id}</b>: {msg.data}</p>
 {/each}
 <button on:click={() => broadcast('Hello!')}>Send</button>
{:else}
 <p>Joining room...</p>
{/if}

Store state:

Field Type Description
joined boolean Whether the room has been joined
members RoomMember[] Current room members
messages Array<{ data: T; member: RoomMember }> Received messages
error Error | null Last error

createPresenceStore

<script>
 import { createPresenceStore } from 'atmosphere.js/svelte';

 const presence = createPresenceStore(
 { url: '/atmosphere/room', transport: 'websocket' },
 'lobby',
 { id: currentUser.id },
 );
</script>
<span>{$presence.count} online</span>
{#each $presence.members as m}
 <span>{m.id}</span>
{/each}

Store state:

Field Type Description
joined boolean Whether we have joined the room
members RoomMember[] Current online members
count number Number of members online

API Summary

Hook / Store React Vue Svelte
Raw subscription useAtmosphere useAtmosphere createAtmosphereStore
Room (messages + presence) useRoom useRoom createRoomStore
Presence only usePresence usePresence createPresenceStore
Provider / context AtmosphereProvider (none needed) (none needed)

All hooks handle:

  • ✅ Automatic connection on mount / first subscriber
  • ✅ Automatic cleanup on unmount / last unsubscribe
  • ✅ Reconnection (via Atmosphere's built-in reconnect)
  • ✅ Full TypeScript generics for message types

Shared Types

interface RoomMember {
 id: string;
 metadata?: Record<string, unknown>;
}
interface PresenceEvent {
 type: 'join' | 'leave';
 room: string;
 member: RoomMember;
}
type ConnectionState = 'disconnected' | 'connected' | 'reconnecting' | 'closed' | 'error';

See Also

Clone this wiki locally

AltStyle によって変換されたページ (->オリジナル) /