fix(room): fix StrictMode reconnect loop, add revokeMessage rollback
- useEffect([wsClient]): remove wsClient from deps to prevent React StrictMode double-mount from disconnecting the real client. First mount connects client-1; StrictMode cleanup disconnects it. Second mount connects client-2; first mount's second cleanup would then disconnect client-2, leaving WS permanently unconnected. Changing to useEffect([]) + optional chaining fixes this. - revokeMessage: add optimistic removal + rollback on server rejection, consistent with editMessage pattern. Previously a failed delete left the message visible with no feedback.
This commit is contained in:
parent
7416f37cec
commit
7989f7ba4b
@ -595,11 +595,17 @@ export function RoomProvider({
|
||||
}, [wsToken]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!wsClientRef.current) return;
|
||||
wsClientRef.current.connect().catch((e) => {
|
||||
// NOTE: intentionally omitted [wsClient] from deps.
|
||||
// In React StrictMode the component mounts twice — if wsClient were a dep,
|
||||
// the first mount's effect would connect client-1, then StrictMode cleanup
|
||||
// would disconnect it, then the second mount's effect would connect client-2,
|
||||
// then immediately the first mount's *second* cleanup would fire and
|
||||
// disconnect client-2 — leaving WS unconnected. Using a ref for the initial
|
||||
// connect avoids this. The client is always ready by the time this runs.
|
||||
wsClientRef.current?.connect().catch((e) => {
|
||||
console.error('[RoomContext] WS connect error:', e);
|
||||
});
|
||||
}, [wsClient]);
|
||||
}, []);
|
||||
|
||||
const connectWs = useCallback(async () => {
|
||||
const client = wsClientRef.current;
|
||||
@ -899,10 +905,25 @@ export function RoomProvider({
|
||||
async (messageId: string) => {
|
||||
const client = wsClientRef.current;
|
||||
if (!client) return;
|
||||
await client.messageRevoke(messageId);
|
||||
setMessages((prev) => prev.filter((m) => m.id !== messageId));
|
||||
// Persist to IndexedDB
|
||||
deleteMessageFromIdb(messageId).catch(() => {});
|
||||
|
||||
// Optimistic removal: hide message immediately
|
||||
let rollbackMsg: MessageWithMeta | null = null;
|
||||
setMessages((prev) => {
|
||||
rollbackMsg = prev.find((m) => m.id === messageId) ?? null;
|
||||
return prev.filter((m) => m.id !== messageId);
|
||||
});
|
||||
|
||||
try {
|
||||
await client.messageRevoke(messageId);
|
||||
deleteMessageFromIdb(messageId).catch(() => {});
|
||||
} catch (err) {
|
||||
// Rollback: restore message on server rejection
|
||||
if (rollbackMsg) {
|
||||
setMessages((prev) => [...prev, rollbackMsg!]);
|
||||
saveMessage(rollbackMsg!).catch(() => {});
|
||||
}
|
||||
handleRoomError('Delete message', err);
|
||||
}
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user