Open seleckis opened 6 months ago
In a component that renders tipTap editor I need to update the presence of the user like this:
const self = useSelf(); useEffect(() => { if (!self || !editor) return; editor.commands.updateUser({ name: self.username, color: self.color, }); }, [self, editor]);
Unfortunately this code makes tiptap editor opened websocket to go mad and infinity send a huge amount of messages.
Hi @seleckis, in this code snippet you posted, are you attempting to update the user presence every time the value of self
is updated? If so, the behaviour you experienced is expected. It's almost like updating the current user's presence every time the user's presence is updated, which triggers an infinite loop of updating presence. If not, do you mind providing more context on what you are trying to achieve with the code snippet? I'd love to help if I can.
I have create this hook:
import { isEqual } from "lodash-es"; import { useSelf as usePresenceSelf } from "y-presence"; export const useSelf = () => { const self = usePresenceSelf(awareness) as YUser; const selfRef = useRef(self); useEffect(() => { if (isEqual(self, selfRef.current)) return; selfRef.current = self; }, [self]); return selfRef.current; };
This is a nice way to ensure selfRef
is only updated if the current user's presence is actually updated. But, there are some minor problems with this approach from what I understand. First of all, React doesn't recommend reading ref.current
during rendering (Link) and second, if your goal is to perform some work when user's presence is updated, I'd recommend subscribing (and then unsubscribing during unmount) to user's awareness using the awaresness.on('update')
or awareness.on('change')
API (Link).
Well, I need to set user data for CollaborationCursor extension. According to documentation it should be set when initializing editor with extensions:
const self = useSelf();
const extensions = useMemo(() => [
Collaboration.configure({
document: ydoc,
fragment: yField,
}),
CollaborationCursor.configure({
provider: yprovider,
user: {
user: self?.username,
color: self?.color,
},
}),
], [yField, self]);
const editor = useEditor({
extensions,
});
but in this case sometimes self?.username returns clientID of current user and does not update user data when useSelf
from y-presence
updates and returns correct user data. That is why I'm using useEffect
to update user data for CollaborationCursor.
I have broken down the object useSelf
gives and discovered that CollaborationCursor sets its own data, maybe that is why useSelf returns a new updated object every time.
So do you suggest to use awareness
events for this case and not useSelf? Alright:
useEffect(() => {
const onChange = ({ added, updated, removed }) => {
console.log(added, updated, removed);
})
awareness.on("change", onChange);
return () => {
awareness.off("change", onChange);
};
}, []);
in this case it gives me only clientID
but not other data like username and color.
Alright, I've ended up with this solution:
export const useAwareness = (cb: (self: YUser | null) => void) => {
useEffect(() => {
const onChange = ({ updated }: { updated: number[] }) => {
if (updated.includes(awareness.clientID)) {
const self = awareness.getLocalState();
cb(self as YUser);
}
};
awareness.on("change", onChange);
return () => {
awareness.off("change", onChange);
};
}, [cb]);
};
...
useAwareness((self) => {
if (!editor || !self?.username) return;
const { username, color } = self;
editor.commands.updateUser({
name: username,
color,
});
});
This works well, updates tiptap collaboration cursor with correct data and does not force websocket to send infinite messages. I was just hoping y-presence
lib could do these things, but maybe I'm wrong.
useSelf works well in most situations. But when I use it with TipTap editor and CollaborationCursor extension here comes an issue:
In a component that renders tipTap editor I need to update the presence of the user like this:
Unfortunately this code makes tiptap editor opened websocket to go mad and infinity send a huge amount of messages.
I have create this hook:
Now update is working as expected and there is no infinite loop of messages anymore.
Should this be added in the y-presence lib? What do you think?