import { useEffect, useLayoutEffect, useRef, useState } from "react"; import "./App.css"; import { Client } from "./ot/client"; import { generateOperations } from "./ot/helpers"; import { getDemoServerInstance } from "./ot/server"; function Editor({ name }: { name: string }) { const clientRef = useRef(null); const [doc, setDoc] = useState(""); const prevDocRef = useRef(""); const [enableSync, setEnableSync] = useState(true); // 初始化client和文档状态 useLayoutEffect(() => { if (!clientRef.current) { clientRef.current = new Client(); clientRef.current.name = name; const initialDoc = clientRef.current.document || ""; prevDocRef.current = initialDoc; setDoc(initialDoc); } // eslint-disable-next-line react-hooks/exhaustive-deps }, []); useEffect(() => { if (!clientRef.current) return; // 定期同步client的文档状态到UI const timer = setInterval(() => { const currentDoc = clientRef.current!.document || ""; if (currentDoc !== prevDocRef.current) { setDoc(currentDoc); prevDocRef.current = currentDoc; } }, 100); return () => clearInterval(timer); }, []); const handleChange = (e: React.ChangeEvent) => { if (!clientRef.current) return; const newValue = e.target.value; // 使用client当前文档状态作为旧值 const oldValue = clientRef.current.document || ""; if (newValue !== oldValue) { // 生成操作集合 const operations = generateOperations(oldValue, newValue); // 按顺序应用操作 operations.forEach((op) => { clientRef.current!.applyClient(op); }); } }; const handleToggleSync = () => { const newValue = !enableSync; setEnableSync(newValue); if (clientRef.current) { clientRef.current.setEnableSync(newValue); } }; return (

Document: