ReactSharedPresence

SharedPresence Introduction

SharePresence is a primitive that syncs signaling information about the user and their client.

Introduction & Concepts

With SharedPresence clients publish data about themselves for every other client (referred to as "peers") to see.

The SharedPresence primitive can be used in React via the useSharedPresence hook.

  1. Each client joins a "room" to exchange information.
  2. Each client can write their own state but can only read information about other clients.
  3. Clients can read both state information (set by the peer client itself) and meta information (set by the server via a JWT token) about their peers in a room.
  4. The meta information can only be set by the server via a JWT that each client passes to the AirState server (meant to signal auth information like username or user_id or even a full user model complete with name and picture)
  5. Each client also has access to connection state of their peers, and time information like last connected.

Hello World

For the "hello world" example, we chose a simple application where we display the peer ids of the peers currently hovering the box.

import { useSharedPresence } from "@airstate/react";

export function App() {
    const { self, setState, others } = useSharedPresence<boolean>({
        peer: 'you@yourself.com',           // IMPORTANT: replace this with something unique
        initialState: false                 // store hover state
    });

    const otherHoveringPeers: string[] =
        Object.values(others)               // others is an object Record<string, Peer>
            .filter(peer => peer.connected) // only display peers that are current connected
            .filter(peer => peer.state)     // only display peers that are hovering
            .map(peer => peer.peer)         // take the peer id.

    return (
        <div
            onMouseEnter={() => setState(true)}
            onMouseLeave={() => setState(false)}

            className={'size-96 bg-amber-200 hover:bg-amber-400'}
        >
            {
                self.state
                    ? <div>YOU</div>
                    : null
            }

            {otherHoveringPeers.map(
                peer => <div>{peer}</div>
            )}
        </div>
    );
}

By default, the unique identifier for this presence "room" is set to be the pathname derived from window.location.href

An important limitation of this is that you can only have at most one SharedPresence instance without an explicitly defined room on a page.

SharedPresence vs SharedState

  • SharedPresence focuses on providing each client with their own state that the client can modify but other clients can read.

  • Example: Say you build a real-time collaborative sticky-note app with SharedState. In order to show the location of each user's cursor, you'd use SharedPresence because it doesn't make sense for clients to be updating another client's cursor position.

  • SharedPresence has the ability to expose immutable state that like user_id or username set by a authoritative server (via JWT passing), but SharedState does not.

Use Cases

With SharedPresence you are welcome to build anything you want where you need each client to expose unique information about itself to facilitate collaboration.

It is typically using to build things like (not an exhaustive list):

  • Real-time Live Cursors (like Miro)
  • User Typing Carets (like Google Docs)
  • "Follow [User]" feature (like Figma)
  • "Mirror [x] Frame" feature (like Figma)