用 Yjs + React 写一个支持协同的 TODO 应用

lxf2023-05-10 01:18:11

大家好,我是前端西瓜哥。

为了测试 Yjs 的协同能力,我实现了支持协同简单的 TODO 应用。

支持的功能

  1. 创建房间;

  2. 新增、删除、完成、清空所有待办;

  3. 撤销重做;

  4. 显示其他用户的光标位置;

技术栈

列一下用到的技术:

  1. Vite + React + TypeScript + React Router;

  2. Yjs、y-websocket:实现协同编辑;

源码

源码放 Github 上了。因为花了一天写的简易 Demo,没有太分模块,代码很稀烂,仅供参考。

github.com/F-star/yjs-…

运行方式

先安装依赖:

pnpm install

然后两个终端分别启动服务端和客户端:

pnpm run server

pnpm run dev

![图片转存失败,建议将图片保存下来直接上传
        
演示
--

简单看看效果。

创建一个房间

 图片(https://mmbiz.qpic.cn/mmbiz_gif/Axu3yFGzpW9OdbgYFK8UYcVsVtIdaiaqyichib3nXPYicoCZCtsMnx2rLEnzjP01HRxjUCxv932TgnK4m0GeMElJSA/640?wx_fmt=gif)

复制这个房间链接,在另一个浏览器里打开。

然后就是一段操作。  

 图片(https://mmbiz.qpic.cn/mmbiz_gif/Axu3yFGzpW9OdbgYFK8UYcVsVtIdaiaqyjS4DD1vsaJ884KFSymqx5K0KGkPYUnvYumpvESu8aeqXXNJarFjicKw/640?wx_fmt=gif)

一些知识点
-----

所有的需要同步的对象都保存在一个 Y.Doc 对象下,在其下会创建 Yjs 的数据类型,比如 YArray、YMap。

]()```
this.ydoc = new Y.Doc();

然后我们需要一个 Provider 去将这个对象的内容同步出去,以及同步回来。

this.provider = new WebsocketProvider(wsUrl, this.roomIdthis.ydoc);

模块之间的解耦,果然还得是发布订阅模式。通过 observer 监听数据的变化,然后同步到组件上。

// 创建顶层的 YArray 对象
this.yTodoItems = this.ydoc.getArray('todoItems');
this.yTodoItems.observe(callback);

// 拿到 YArray 对应的普通数组对象,更新组件的内部状态
yjsClient.onTodoItemsChange((event) => {
  setTodoItems(event.target.toArray());
});

对于要修改一个 YArray 下一个普通对象的情况,不能修改这个普通对象的属性,它不会触发 observe 事件。我们有两种解法。

第一种方案是从 YArray 对象下删除对应索引位置的对象,然后在这个地方再插入一个修改了属性的拷贝对象。

toggleTodoItemDone(index: number) {
  // 下面的写法无法触发 observe
  // const item = this.yTodoItems.get(index);
  // item.done = !item.done;

  // 下面的写法可以触发 observe
  const item = this.yTodoItems.get(index);
  this.yTodoItems.delete(index, 1);
  this.yTodoItems.insert(index, [
    {
      id: item.id,
      text: item.text,
      done: !item.done,
    },
  ]);
}

第二种方案是可以将这个普通对象换成 Y.Map 对象嵌入 YArray 下,通过它的 API 修改属性,然后用 YArray 的 observeDeep,不能再用 observe 了。

Yjs 的 TypeScript 类型支持不太完善。有些类型太宽泛,比如 YMap 只能定一个类似 Map 的类型,不能传一个特定结构的 interface,要自己用 as 手动强转类型。

另外,一些包的类型也无法使用,虽然我看到这个包下是有类型文件的。不知道是不是 vite 的问题。

用 Yjs + React 写一个支持协同的 TODO 应用

结尾

Yjs 确实很强大,只要接上 Yjs 的数据结构类型,就能快速实现一个分布式的协同编辑应用。

我是前端西瓜哥,欢迎关注我,学习更多前端知识。


相关阅读,

Yjs + quill:快速实现支持协同编辑的富文本编辑器

图形编辑器:历史记录设计

本网站是一个以CSS、JavaScript、Vue、HTML为核心的前端开发技术网站。我们致力于为广大前端开发者提供专业、全面、实用的前端开发知识和技术支持。 在本网站中,您可以学习到最新的前端开发技术,了解前端开发的最新趋势和最佳实践。我们提供丰富的教程和案例,让您可以快速掌握前端开发的核心技术和流程。 本网站还提供一系列实用的工具和插件,帮助您更加高效地进行前端开发工作。我们提供的工具和插件都经过精心设计和优化,可以帮助您节省时间和精力,提升开发效率。 除此之外,本网站还拥有一个活跃的社区,您可以在社区中与其他前端开发者交流技术、分享经验、解决问题。我们相信,社区的力量可以帮助您更好地成长和进步。 在本网站中,您可以找到您需要的一切前端开发资源,让您成为一名更加优秀的前端开发者。欢迎您加入我们的大家庭,一起探索前端开发的无限可能!