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

news/2024/7/15 18:29:03 标签: react.js, javascript, 前端

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

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

支持的功能

  1. 创建房间;
  2. 新增、删除、完成、清空所有待办;
  3. 撤销重做;
  4. 显示其他用户的光标位置;

技术栈

列一下用到的技术:

  1. Vite + React + TypeScript + React Router;
  2. Yjs、y-websocket:实现协同编辑;

源码

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

https://github.com/F-star/yjs-react-todo-app

运行方式

先安装依赖:

pnpm install

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

pnpm run server
pnpm run dev

演示

简单看看效果。

创建一个房间

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

然后就是一顿操作。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tzuEEyTO-1683300859459)(https://fe-watermelon.oss-cn-shenzhen.aliyuncs.com/%E6%B5%8B%E8%AF%95.gif)]

一些知识点

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

this.ydoc = new Y.Doc();

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

this.provider = new WebsocketProvider(wsUrl, this.roomId, this.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 确实很强大,只要接上 Yjs 的数据结构类型,就能快速实现一个分布式的协同编辑应用。

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


http://www.niftyadmin.cn/n/292868.html

相关文章

基于SpringBoot+Vue实现的体检录入系统

【简介】 本体检信息录入系统采用前端:vue;后端:springbootmybatis-plusredismysql技术架构开发,前后端分离,容易上手。除了基本的体检结果查询、录入及导出外,在录入中还能对录入信息进行智能计算。 【功…

【Docker】命令大全

文章目录 基本命令镜像相关docker imagesdocker pulldocker rmidocker rundocker build镜像发布镜像常用命令 容器相关docker psdocker logs容器常用命令 数据卷相关网络相关compose相关swarm相关 基本命令 命令说明docker version显示版本信息docker info显示系统信息&#x…

Spark学习笔记【shuffle】

本文基本上是大数据处理框架Apache Spark设计与实现的Shuffle部分的学习。以及Spark基础知识Bambrow Shuffle解决啥问题 上游和下游,不同stage,不同的task之间是如何传递数据的。ShuffleManager管理ShuffleWrite和ShuffleRead 分为两个阶段&#xff1…

Android - 约束布局 ConstraintLayout

一、概念 解决布局嵌套过多的问题,采用方向约束的方式对控件进行定位。 二、位置约束 2.1 位置 至少要保证水平和垂直方向都至少有一个约束才能确定控件的位置。 layout_constraintLeft_toLeftOf我的左边,与XXX左边对齐。layout_constraintLeft_toRight…

(二)【平衡小车制作】电机驱动(超详解)

一、硬件设计 1.直流减速电机   直流减速电机,即齿轮减速电机,是在普通直流电机的基础上,加上配套齿轮减速箱。齿轮减速箱的作用是,提供较低的转速,较大的力矩。  简单的来说,STM32分配两个IO口给一个…

【算法题】2401. 最长优雅子数组

插: 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。 坚持不懈,越努力越幸运,大家一起学习鸭~~~ 题目: 给你一个由 正 整数组成的数组 num…

BetaFlight统一硬件配置文件研读之dma命令

BetaFlight统一硬件配置文件研读之dma命令 1. 源由2. 代码分析2.1 cliDma2.2 showDma2.3 cliDmaopt 3. 实例分析4. 配置情况4.1 dma4.2 dma show4.3 dma device list4.4 dma pin list4.5 dma device id4.5.1 dma adc id4.5.2 dma TIMUP id4.5.3 dma pin id 4.6 dma device id s…

如何优化文件大小、理解程度,减少不必要的字符,最简文件的标准如何产生,笔记的合理性

文件优化要点(非代码) 模块化引用省去文字头,命名空间缩写不缩小范围减少字符重命名引用和寻找新逻辑算法改进编码,减少不可见及多余字符减少重复的文件或内容以及字符,确保有且只有一份(备份除外)寻找更好的替代品,1个代替2个以…