CRDTを用いた共同編集機能をHooksで簡単に使えるRoom Service(Beta版)を使う
CRDT とは何か
Google Docs など共同編集機能があるシステムの裏で文章のコンフリクトをリアルタイムに競合解決を行っているアルゴリズムの一つに、CRDT (Conflict-free Replicated Data Type)というものがあります。
参考
CRDT の他に、OT(Operational Transformation)、日本語では操作変換と呼ばれるものもあり、こちらは 1989 年頃には存在していて歴史が古く、Google Wave や Google Docs などで採用されています
参考
Google Wave などを開発していた中の人のブログ
「I was wrong. CRDTs are the future」という強いタイトルの記事
CRDT の JS 実装で有名なものに yjs があります(Star 2.8k)
yjs には CodeMirror や Monaco など主要なエディターライブラリとのバインディングに対応していて、クライアント間での通信に必要な設定も WebRTC や、WebSocket などから選択することができます
それらのアルゴリズムや、必要となるバックエンドを抽象化し、React Hooks で超簡単に扱えるようにしたサービスが Room Service です
Discordでは、数週間後に価格設定を初めて行きたいみたいな話を聞きました。
サンプルプロジェクトを動かしてみる
yarn create next-app --example https://github.com/getroomservice/examples --example-path next.js-todolist
Room Service に登録して入手した api キーを.env に追加します
echo ROOMSERVICE_API_KEY=APIKEY >> .env
Room Service では、map と list なデータ構造を使うことができ、useMap と useList の hooks が用意されていて、このサンプルアプリでは useList を使って todo を管理しています
const [todos, list] = useList("my-room", "todos");
この場合、my-room を使用している todos リストを全てのユーザーからの変更をリアルタイムに更新します。これだけです。。。
_app.tsx では Room Service で使うセッショントークンを生成しています。
このサンプルアプリには使われていませんが、Room Service にはユーザーがアクティブの状態の時にだけ有効になる Presence という Hooks があります。
これはユーザーが退室するとそのデータは削除されるため、「誰が部屋にいるか」のユーザーリストや、カーソル位置の共有などに最適でそれらが簡単に実装できます!
この Presence を使ったサンプルアプリをみてみます
.env に Room Service の API キーを追加して
echo ROOMSERVICE_API_KEY=APIKEY >> .env
yarn dev でマウスカーソルの座標を共有するアプリが立ち上がります
不要なテキストを消してみるとマウスカーソル位置の共有に必要なコードはたったこれだけです。usePresence で my-room 内の positions という Presence を参照する hooks を生やすだけでユーザーがアクティブの時にのみ有効なデータを使えました
import { usePresence } from "@roomservice/react";
import { useEffect } from "react";
export default function Home() {
const [positions, positionsClient] = usePresence("my-room", "positions");
useEffect(() => {
window.onmousemove = (e: MouseEvent) => {
positionsClient.set({ x: e.clientX, y: e.clientY });
};
}, []);
return <div>Positions: {JSON.stringify(positions)}</div>;
}
最後に、useMap で textarea、usePresence でマウスカーソルがリアルタイムに
に共有されるサンプルプロジェクトを作ってみましたので参考に!
Discussion