From 7945343d0785fca8e0e1fe5b2fa8ef94abb026ba Mon Sep 17 00:00:00 2001 From: Shun Miyazawa Date: Thu, 28 Nov 2024 08:51:39 +0000 Subject: [PATCH 1/2] Refactor useIsYjsEnabled to use useSWRStatic --- .../PageEditor/EditorNavbar/EditorNavbar.tsx | 2 +- .../client/components/PageEditor/PageEditor.tsx | 2 +- .../client/services/use-single-editor-mode.ts | 2 +- apps/app/src/client/services/yjs.ts | 17 ++++++++++------- 4 files changed, 13 insertions(+), 10 deletions(-) diff --git a/apps/app/src/client/components/PageEditor/EditorNavbar/EditorNavbar.tsx b/apps/app/src/client/components/PageEditor/EditorNavbar/EditorNavbar.tsx index bc339cd946e..c6f3b40a733 100644 --- a/apps/app/src/client/components/PageEditor/EditorNavbar/EditorNavbar.tsx +++ b/apps/app/src/client/components/PageEditor/EditorNavbar/EditorNavbar.tsx @@ -12,7 +12,7 @@ const moduleClass = styles['editor-navbar'] ?? ''; export const EditorNavbar = (): JSX.Element => { const { data: editingUsers } = useEditingUsers(); - const isYjsEnabled = useIsYjsEnabled(); + const { data: isYjsEnabled } = useIsYjsEnabled(); const editorCondition = useMemo(() => { if (isYjsEnabled) { diff --git a/apps/app/src/client/components/PageEditor/PageEditor.tsx b/apps/app/src/client/components/PageEditor/PageEditor.tsx index 6ef56aec967..c3efc50f3eb 100644 --- a/apps/app/src/client/components/PageEditor/PageEditor.tsx +++ b/apps/app/src/client/components/PageEditor/PageEditor.tsx @@ -111,7 +111,7 @@ export const PageEditor = React.memo((props: Props): JSX.Element => { const { data: user } = useCurrentUser(); const { onEditorsUpdated } = useEditingUsers(); const onConflict = useConflictResolver(); - const isYjsEnabled = useIsYjsEnabled(); + const { data: isYjsEnabled } = useIsYjsEnabled(); const { data: reservedNextCaretLine, mutate: mutateReservedNextCaretLine } = useReservedNextCaretLine(); diff --git a/apps/app/src/client/services/use-single-editor-mode.ts b/apps/app/src/client/services/use-single-editor-mode.ts index 3f237ae642f..39223a73162 100644 --- a/apps/app/src/client/services/use-single-editor-mode.ts +++ b/apps/app/src/client/services/use-single-editor-mode.ts @@ -16,7 +16,7 @@ export const useSingleEditorMode = (): void => { const { data: currentPage } = useSWRxCurrentPage(); const { data: yjsMaxBodyLength } = useYjsMaxBodyLength(); const { data: codeMirrorEditor } = useCodeMirrorEditorIsolated(GlobalCodeMirrorEditorKey.MAIN); - const isYjsEnabled = useIsYjsEnabled(); + const { data: isYjsEnabled } = useIsYjsEnabled(); const [shouldRecalculate, setShouldRecalculate] = useState(false); diff --git a/apps/app/src/client/services/yjs.ts b/apps/app/src/client/services/yjs.ts index 64c6842c483..944031ada4d 100644 --- a/apps/app/src/client/services/yjs.ts +++ b/apps/app/src/client/services/yjs.ts @@ -2,26 +2,29 @@ import { useState, useEffect, useCallback, } from 'react'; +import { useSWRStatic } from '@growi/core/dist/swr'; import { useRouter } from 'next/router'; +import type { SWRResponse } from 'swr'; import { useYjsMaxBodyLength } from '~/stores-universal/context'; import { EditorMode, useEditorMode } from '~/stores-universal/ui'; import { useSWRxCurrentPage } from '~/stores/page'; -export const useIsYjsEnabled = (): boolean | undefined => { +export const useIsYjsEnabled = (): SWRResponse => { const { data: yjsMaxBodyLength } = useYjsMaxBodyLength(); const { data: currentPage } = useSWRxCurrentPage(); const { data: editorMode } = useEditorMode(); - const [isYjsEnabled, setIsYjsEnabled] = useState(undefined); const [shouldRecalculate, setShouldRecalculate] = useState(false); + const swrResponse = useSWRStatic('isYjsEnabled', undefined); + const router = useRouter(); const onRouterChangeComplete = useCallback(() => { - setIsYjsEnabled(undefined); setShouldRecalculate(false); - }, []); + swrResponse.mutate(undefined); + }, [swrResponse]); useEffect(() => { router.events.on('routeChangeComplete', onRouterChangeComplete); @@ -36,16 +39,16 @@ export const useIsYjsEnabled = (): boolean | undefined => { } else { setShouldRecalculate(false); - setIsYjsEnabled(undefined); + swrResponse.mutate(undefined); } }, [editorMode]); useEffect(() => { if (shouldRecalculate && currentPage?.revision?.body != null && yjsMaxBodyLength != null) { setShouldRecalculate(false); - setIsYjsEnabled(currentPage.revision.body.length <= yjsMaxBodyLength); + swrResponse.mutate(currentPage.revision.body.length <= yjsMaxBodyLength); } }, [currentPage?.revision?.body, shouldRecalculate, yjsMaxBodyLength]); - return isYjsEnabled; + return swrResponse; }; From 66c599cbaecc3869f50d29426629c02ed342b857 Mon Sep 17 00:00:00 2001 From: Shun Miyazawa Date: Fri, 29 Nov 2024 02:18:36 +0000 Subject: [PATCH 2/2] Shift to SingleEditorMode on yjsConnectionError --- apps/app/src/client/components/PageEditor/PageEditor.tsx | 7 ++++++- .../components/PageEditor/PageEditorMainSwitcher.tsx | 5 +++-- .../src/client/stores/use-collaborative-editor-mode.ts | 7 ++++++- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/apps/app/src/client/components/PageEditor/PageEditor.tsx b/apps/app/src/client/components/PageEditor/PageEditor.tsx index b2c8e944a93..921f5511b50 100644 --- a/apps/app/src/client/components/PageEditor/PageEditor.tsx +++ b/apps/app/src/client/components/PageEditor/PageEditor.tsx @@ -112,7 +112,7 @@ export const PageEditor = React.memo((props: Props): JSX.Element => { const { data: user } = useCurrentUser(); const { onEditorsUpdated } = useEditingUsers(); const onConflict = useConflictResolver(); - const { data: isYjsEnabled } = useIsYjsEnabled(); + const { data: isYjsEnabled, mutate: mutateIsYjsEnabled } = useIsYjsEnabled(); const { addChangeDetector } = useUnsavedChanges(); const { data: reservedNextCaretLine, mutate: mutateReservedNextCaretLine } = useReservedNextCaretLine(); @@ -135,6 +135,10 @@ export const PageEditor = React.memo((props: Props): JSX.Element => { const currentRevisionOrigin = currentPage?.revision?.origin; const isRevisionIdRequiredForPageUpdate = currentRevisionOrigin === undefined || currentRevisionOrigin === Origin.EditorSingle || isYjsEnabled === false; + const yjsConnectionErrorHandler = useCallback(() => { + mutateIsYjsEnabled(false); + }, [mutateIsYjsEnabled]); + const initialValueRef = useRef(''); const initialValue = useMemo(() => { if (!isNotFound) { @@ -397,6 +401,7 @@ export const PageEditor = React.memo((props: Props): JSX.Element => { pageId={pageId ?? undefined} editorSettings={editorSettings} onEditorsUpdated={onEditorsUpdated} + onYjsConnectionError={yjsConnectionErrorHandler} isYjsEnabled={isYjsEnabled} cmProps={cmProps} /> diff --git a/apps/app/src/client/components/PageEditor/PageEditorMainSwitcher.tsx b/apps/app/src/client/components/PageEditor/PageEditorMainSwitcher.tsx index 44008f8d47f..6612f6584df 100644 --- a/apps/app/src/client/components/PageEditor/PageEditorMainSwitcher.tsx +++ b/apps/app/src/client/components/PageEditor/PageEditorMainSwitcher.tsx @@ -16,17 +16,18 @@ type PageEditorSwitcherProps = CodeMirrorEditorProps & { user?: IUserHasId pageId?: string onEditorsUpdated?: (userList: IUserHasId[]) => void, + onYjsConnectionError?: () => void }; export const PageEditorMainSwitcher = React.memo((props: PageEditorSwitcherProps): JSX.Element => { const { - isYjsEnabled, cmProps, user, pageId, onEditorsUpdated, ...otherProps + isYjsEnabled, cmProps, user, pageId, onEditorsUpdated, onYjsConnectionError, ...otherProps } = props; const { data: codeMirrorEditor } = useCodeMirrorEditorIsolated(GlobalCodeMirrorEditorKey.MAIN); useSingleEditorMode(); - useCollaborativeEditorMode(isYjsEnabled ?? false, user, pageId, onEditorsUpdated, codeMirrorEditor); + useCollaborativeEditorMode(isYjsEnabled ?? false, user, pageId, onEditorsUpdated, onYjsConnectionError, codeMirrorEditor); const cmPropsOverride = useMemo(() => deepmerge( cmProps ?? {}, diff --git a/packages/editor/src/client/stores/use-collaborative-editor-mode.ts b/packages/editor/src/client/stores/use-collaborative-editor-mode.ts index 5ebd2fb0493..c6695264713 100644 --- a/packages/editor/src/client/stores/use-collaborative-editor-mode.ts +++ b/packages/editor/src/client/stores/use-collaborative-editor-mode.ts @@ -22,6 +22,7 @@ export const useCollaborativeEditorMode = ( user?: IUserHasId, pageId?: string, onEditorsUpdated?: (userList: IUserHasId[]) => void, + onYjsConnectionError?: () => void, codeMirrorEditor?: UseCodeMirrorEditor, ): void => { const [ydoc, setYdoc] = useState(null); @@ -96,6 +97,10 @@ export const useCollaborativeEditorMode = ( } }); + socketIOProvider.on('connection-error', () => { + onYjsConnectionError?.(); + }); + // update args type see: SocketIOProvider.Awareness.awarenessUpdate socketIOProvider.awareness.on('update', (update: { added: unknown[]; removed: unknown[]; }) => { const { added, removed } = update; @@ -106,7 +111,7 @@ export const useCollaborativeEditorMode = ( }); setProvider(socketIOProvider); - }, [onEditorsUpdated, pageId, provider, socket, user, ydoc]); + }, [onYjsConnectionError, onEditorsUpdated, pageId, provider, socket, user, ydoc]); // Setup Ydoc Extensions useEffect(() => {