React

Room Service comes with a native React client. You should use this client instead of the @roomservice/browser client.

Getting Started

Install the client with:

1yarn add @roomservice/react
2
3# or
4
5npm install --save @roomservice/react

Then, at the root of your project, add a RoomServiceProvider. The clientOptions are the same you'd pass into the existing RoomService class:

1// app.js
2import { RoomServiceProvider } from "@roomservice/react";
3
4function App() {
5 return (
6 <RoomServiceProvider clientParameters={{ auth: "/my/auth/webhook" }}>
7 {/* ... */}
8 </RoomServiceProvider>
9 );
10}
11

Then, from any child component, you can access Maps, Lists, and Presence keys via hooks.

Maps

While the room is attempting to connect (or failing to connect), the map will be undefined.

1import { useMap } from "@roomservice/react";
2
3function CoolComponent() {
4 const [map, setMap] = useMap("myRoom", "myMap");
5
6 if (!map) return <div>Loading...</div>;
7
8 function onChange(e) {
9 setMap(map.set("name", e.target.value));
10 }
11
12 return <input value={map.get("name")} onChange={onChange} />;
13}

Lists

While the room is attempting to connect (or failing to connect), the list will be undefined.

1import { useList } from "@roomservice/react";
2
3function CoolComponent() {
4 const [list, setList] = useList("myRoom", "myList");
5
6 if (!list) return <div>Loading...</div>;
7
8 function onClick() {
9 setList(list.push("new todo!"));
10 }
11
12 return (
13 <ul>
14 {list.map((val, _, key) => (
15 <li key={key}>{val}</li>
16 ))}
17 <button onClick={onClick}>Click me</button>
18 </ul>
19 );
20}

Presence

usePresence returns an object where each key is the user id and each value is the current value for the key.

1import { usePresence } from "@roomservice/react";
2
3function Example() {
4 const [names, setMyName] = usePresence("myRoom", "names");
5
6 console.log(names) // { "user-123": "alice", "user-321": "berry" }
7
8 // ...
9}

When a user leaves the room, the presence key expires. So you can use this for expiring effects, like mouse cursors, presence indicators, shared highlighting effects, or anything else you might think of!

For example, here's a small mouse cursor demo:

1import { usePresence } from "@roomservice/react";
2
3function Cursors() {
4 const [positions, setMyPosition] = usePresence("myRoom", "positions");
5
6 useEffect(() => {
7 const listener = (e) => {
8 setMyPosition({
9 x: e.clientX,
10 y: e.clientY,
11 });
12 };
13 document.addEventListener("mousemove", listener);
14 return () => document.removeEventListener("mousemove", listener);
15 }, []);
16
17 return (
18 <>
19 {Object.entries(positions).map(([key, val]) => (
20 <Cursor key={key} x={val.x} y={val.y} />
21 ))}
22 </>
23 );
24}

Accessing the room directly

If you'd like more control, you can always access the room directly with useRoom. You can use this to build your own hooks and have more control over the state changes.

1import { useRoom } from "@roomservice/react"
2
3function CoolComponent() {
4 const room = useRoom("cool-room")
5
6 if (!room) return <div>Loading...</div>
7
8 return //...
9}
1import { useRoom } from "@roomservice/react"
2
3function useCustomHook() {
4 const room = useRoom("cool-room")
5
6 useEffect(() => {
7 if (!room) return;
8 const map = room.map("custom")
9
10 room.subscribe(map, nextMap => {
11 // ... do something with nextMap
12 })
13 }, [room])
14
15 // ...
16}