From 2817740c94281cef5c4fde8b8e3d60bd0c9024a4 Mon Sep 17 00:00:00 2001 From: Tilman Vatteroth Date: Thu, 6 Oct 2022 22:48:36 +0200 Subject: [PATCH] feat(renderer): Use callback instead of redux for renderer ready Signed-off-by: Tilman Vatteroth --- .../document-read-only-page-content.tsx | 4 +- .../note-info/note-info-line-word-count.tsx | 13 ++--- .../editor-document-renderer.tsx | 4 +- .../use-send-dark-mode-status-to-renderer.ts | 8 ++-- .../hooks/use-send-markdown-to-renderer.ts | 8 ++-- .../hooks/use-send-scroll-state.ts | 19 ++++---- .../renderer-pane/render-iframe.tsx | 27 +++++++---- .../hooks/use-intro-page-content.ts | 22 --------- .../intro-page/intro-custom-content.tsx | 47 ++++++++----------- .../hooks/use-effect-on-renderer-ready.ts | 23 --------- .../hooks/use-send-to-renderer.ts | 19 ++++---- .../slide-show-page-content.tsx | 6 ++- 12 files changed, 82 insertions(+), 118 deletions(-) delete mode 100644 src/components/intro-page/hooks/use-intro-page-content.ts delete mode 100644 src/components/render-page/window-post-message-communicator/hooks/use-effect-on-renderer-ready.ts diff --git a/src/components/document-read-only-page/document-read-only-page-content.tsx b/src/components/document-read-only-page/document-read-only-page-content.tsx index ef37e4928..ea273b52a 100644 --- a/src/components/document-read-only-page/document-read-only-page-content.tsx +++ b/src/components/document-read-only-page/document-read-only-page-content.tsx @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file) + * SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file) * * SPDX-License-Identifier: AGPL-3.0-only */ @@ -11,6 +11,7 @@ import { DocumentInfobar } from './document-infobar' import { RenderIframe } from '../editor-page/renderer-pane/render-iframe' import { RendererType } from '../render-page/window-post-message-communicator/rendering-message' import { useTrimmedNoteMarkdownContentWithoutFrontmatter } from '../../hooks/common/use-trimmed-note-markdown-content-without-frontmatter' +import { setRendererStatus } from '../../redux/renderer-status/methods' /** * Renders the read-only version of a note with a header bar that contains information about the note. @@ -29,6 +30,7 @@ export const DocumentReadOnlyPageContent: React.FC = () => { markdownContentLines={markdownContentLines} onFirstHeadingChange={updateNoteTitleByFirstHeading} rendererType={RendererType.DOCUMENT} + onRendererStatusChange={setRendererStatus} /> ) diff --git a/src/components/editor-page/document-bar/note-info/note-info-line-word-count.tsx b/src/components/editor-page/document-bar/note-info/note-info-line-word-count.tsx index 59c05033b..ac871289c 100644 --- a/src/components/editor-page/document-bar/note-info/note-info-line-word-count.tsx +++ b/src/components/editor-page/document-bar/note-info/note-info-line-word-count.tsx @@ -5,7 +5,7 @@ */ import type { PropsWithChildren } from 'react' -import React, { useCallback, useState } from 'react' +import React, { useCallback, useEffect, useState } from 'react' import { Trans, useTranslation } from 'react-i18next' import { ShowIf } from '../../../common/show-if/show-if' import { NoteInfoLine } from './note-info-line' @@ -14,8 +14,8 @@ import { useEditorToRendererCommunicator } from '../../render-context/editor-to- import type { OnWordCountCalculatedMessage } from '../../../render-page/window-post-message-communicator/rendering-message' import { CommunicationMessageType } from '../../../render-page/window-post-message-communicator/rendering-message' import { useEditorReceiveHandler } from '../../../render-page/window-post-message-communicator/hooks/use-editor-receive-handler' -import { useEffectOnRendererReady } from '../../../render-page/window-post-message-communicator/hooks/use-effect-on-renderer-ready' import { cypressId } from '../../../../utils/cypress-attribute' +import { useApplicationState } from '../../../../hooks/common/use-application-state' /** * Creates a new info line for the document information dialog that holds the @@ -31,11 +31,12 @@ export const NoteInfoLineWordCount: React.FC> = () => useCallback((values: OnWordCountCalculatedMessage) => setWordCount(values.words), [setWordCount]) ) - useEffectOnRendererReady( - useCallback(() => { + const rendererReady = useApplicationState((state) => state.rendererStatus.rendererReady) + useEffect(() => { + if (rendererReady) { editorToRendererCommunicator.sendMessageToOtherSide({ type: CommunicationMessageType.GET_WORD_COUNT }) - }, [editorToRendererCommunicator]) - ) + } + }, [editorToRendererCommunicator, rendererReady]) return ( diff --git a/src/components/editor-page/editor-document-renderer/editor-document-renderer.tsx b/src/components/editor-page/editor-document-renderer/editor-document-renderer.tsx index 4effbd940..70fd0555a 100644 --- a/src/components/editor-page/editor-document-renderer/editor-document-renderer.tsx +++ b/src/components/editor-page/editor-document-renderer/editor-document-renderer.tsx @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file) + * SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file) * * SPDX-License-Identifier: AGPL-3.0-only */ @@ -14,6 +14,7 @@ import { RendererType } from '../../render-page/window-post-message-communicator import { useSetCheckboxInEditor } from './hooks/use-set-checkbox-in-editor' import { useOnScrollWithLineOffset } from './hooks/use-on-scroll-with-line-offset' import { useScrollStateWithoutLineOffset } from './hooks/use-scroll-state-without-line-offset' +import { setRendererStatus } from '../../../redux/renderer-status/methods' export type EditorDocumentRendererProps = Omit< RenderIframeProps, @@ -42,6 +43,7 @@ export const EditorDocumentRenderer: React.FC = ({ onTaskCheckedChange={setCheckboxInEditor} rendererType={noteType === NoteType.SLIDE ? RendererType.SLIDESHOW : RendererType.DOCUMENT} markdownContentLines={trimmedContentLines} + onRendererStatusChange={setRendererStatus} /> ) } diff --git a/src/components/editor-page/renderer-pane/hooks/use-send-dark-mode-status-to-renderer.ts b/src/components/editor-page/renderer-pane/hooks/use-send-dark-mode-status-to-renderer.ts index fd9dbd5e6..d451b38e5 100644 --- a/src/components/editor-page/renderer-pane/hooks/use-send-dark-mode-status-to-renderer.ts +++ b/src/components/editor-page/renderer-pane/hooks/use-send-dark-mode-status-to-renderer.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file) + * SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file) * * SPDX-License-Identifier: AGPL-3.0-only */ @@ -13,8 +13,9 @@ import { useSendToRenderer } from '../../../render-page/window-post-message-comm * Sends the current dark mode setting to the renderer. * * @param forcedDarkMode Overwrites the value from the global application states if set. + * @param rendererReady Defines if the target renderer is ready */ -export const useSendDarkModeStatusToRenderer = (forcedDarkMode?: boolean): void => { +export const useSendDarkModeStatusToRenderer = (forcedDarkMode: boolean | undefined, rendererReady: boolean): void => { const savedDarkMode = useIsDarkModeActivated() useSendToRenderer( @@ -24,6 +25,7 @@ export const useSendDarkModeStatusToRenderer = (forcedDarkMode?: boolean): void activated: forcedDarkMode ?? savedDarkMode }), [forcedDarkMode, savedDarkMode] - ) + ), + rendererReady ) } diff --git a/src/components/editor-page/renderer-pane/hooks/use-send-markdown-to-renderer.ts b/src/components/editor-page/renderer-pane/hooks/use-send-markdown-to-renderer.ts index 0c28a8e54..92a5d4c50 100644 --- a/src/components/editor-page/renderer-pane/hooks/use-send-markdown-to-renderer.ts +++ b/src/components/editor-page/renderer-pane/hooks/use-send-markdown-to-renderer.ts @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file) + * SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file) * * SPDX-License-Identifier: AGPL-3.0-only */ @@ -12,8 +12,9 @@ import { CommunicationMessageType } from '../../../render-page/window-post-messa * Sends the given markdown content to the renderer. * * @param markdownContentLines The markdown content to send. + * @param rendererReady Defines if the target renderer is ready */ -export const useSendMarkdownToRenderer = (markdownContentLines: string[]): void => { +export const useSendMarkdownToRenderer = (markdownContentLines: string[], rendererReady: boolean): void => { return useSendToRenderer( useMemo( () => ({ @@ -21,6 +22,7 @@ export const useSendMarkdownToRenderer = (markdownContentLines: string[]): void content: markdownContentLines }), [markdownContentLines] - ) + ), + rendererReady ) } diff --git a/src/components/editor-page/renderer-pane/hooks/use-send-scroll-state.ts b/src/components/editor-page/renderer-pane/hooks/use-send-scroll-state.ts index 10dd8114b..af06a49a7 100644 --- a/src/components/editor-page/renderer-pane/hooks/use-send-scroll-state.ts +++ b/src/components/editor-page/renderer-pane/hooks/use-send-scroll-state.ts @@ -4,12 +4,12 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import { useCallback, useRef } from 'react' +import { useEffect, useRef } from 'react' import type { ScrollState } from '../../synced-scroll/scroll-props' import { CommunicationMessageType } from '../../../render-page/window-post-message-communicator/rendering-message' -import { useEffectOnRendererReady } from '../../../render-page/window-post-message-communicator/hooks/use-effect-on-renderer-ready' import equal from 'fast-deep-equal' import { useEditorToRendererCommunicator } from '../../render-context/editor-to-renderer-communicator-context-provider' +import { useApplicationState } from '../../../../hooks/common/use-application-state' /** * Sends the given {@link ScrollState scroll state} to the renderer if the content changed. @@ -19,13 +19,12 @@ import { useEditorToRendererCommunicator } from '../../render-context/editor-to- export const useSendScrollState = (scrollState: ScrollState | undefined): void => { const iframeCommunicator = useEditorToRendererCommunicator() const oldScrollState = useRef(undefined) + const rendererReady = useApplicationState((state) => state.rendererStatus.rendererReady) - useEffectOnRendererReady( - useCallback(() => { - if (scrollState && !equal(scrollState, oldScrollState.current)) { - oldScrollState.current = scrollState - iframeCommunicator.sendMessageToOtherSide({ type: CommunicationMessageType.SET_SCROLL_STATE, scrollState }) - } - }, [iframeCommunicator, scrollState]) - ) + useEffect(() => { + if (rendererReady && scrollState && !equal(scrollState, oldScrollState.current)) { + oldScrollState.current = scrollState + iframeCommunicator.sendMessageToOtherSide({ type: CommunicationMessageType.SET_SCROLL_STATE, scrollState }) + } + }, [iframeCommunicator, rendererReady, scrollState]) } diff --git a/src/components/editor-page/renderer-pane/render-iframe.tsx b/src/components/editor-page/renderer-pane/render-iframe.tsx index dcf80adaf..0674e890e 100644 --- a/src/components/editor-page/renderer-pane/render-iframe.tsx +++ b/src/components/editor-page/renderer-pane/render-iframe.tsx @@ -17,9 +17,7 @@ import { CommunicationMessageType } from '../../render-page/window-post-message- import { useEditorToRendererCommunicator } from '../render-context/editor-to-renderer-communicator-context-provider' import { useForceRenderPageUrlOnIframeLoadCallback } from './hooks/use-force-render-page-url-on-iframe-load-callback' import { CommunicatorImageLightbox } from './communicator-image-lightbox' -import { setRendererStatus } from '../../../redux/renderer-status/methods' import { useEditorReceiveHandler } from '../../render-page/window-post-message-communicator/hooks/use-editor-receive-handler' -import { useIsRendererReady } from '../../render-page/window-post-message-communicator/hooks/use-is-renderer-ready' import { useSendDarkModeStatusToRenderer } from './hooks/use-send-dark-mode-status-to-renderer' import { useSendMarkdownToRenderer } from './hooks/use-send-markdown-to-renderer' import { useSendScrollState } from './hooks/use-send-scroll-state' @@ -33,6 +31,7 @@ export interface RenderIframeProps extends RendererProps { rendererType: RendererType forcedDarkMode?: boolean frameClasses?: string + onRendererStatusChange?: undefined | ((rendererReady: boolean) => void) } const log = new Logger('RenderIframe') @@ -51,6 +50,7 @@ const log = new Logger('RenderIframe') * @param frameClasses CSS classes that should be applied to the iframe * @param rendererType The {@link RendererType type} of the renderer to use. * @param forcedDarkMode If set, the dark mode will be set to the given value. Otherwise, the dark mode won't be changed. + * @param onRendererStatusChange Callback that is fired when the renderer in the iframe is ready */ export const RenderIframe: React.FC = ({ markdownContentLines, @@ -61,20 +61,25 @@ export const RenderIframe: React.FC = ({ onMakeScrollSource, frameClasses, rendererType, - forcedDarkMode + forcedDarkMode, + onRendererStatusChange }) => { + const [rendererReady, setRendererReady] = useState(false) const frameReference = useRef(null) const rendererBaseUrl = useBaseUrl(ORIGIN.RENDERER) const iframeCommunicator = useEditorToRendererCommunicator() const resetRendererReady = useCallback(() => { log.debug('Reset render status') - setRendererStatus(false) + setRendererReady(false) }, []) - const rendererReady = useIsRendererReady() const onIframeLoad = useForceRenderPageUrlOnIframeLoadCallback(frameReference, resetRendererReady) const [frameHeight, setFrameHeight] = useState(0) - useEffect(() => () => setRendererStatus(false), [iframeCommunicator]) + useEffect(() => { + onRendererStatusChange?.(rendererReady) + }, [onRendererStatusChange, rendererReady]) + + useEffect(() => () => setRendererReady(false), [iframeCommunicator]) useEffect(() => { if (!rendererReady) { @@ -108,7 +113,9 @@ export const RenderIframe: React.FC = ({ useEditorReceiveHandler( CommunicationMessageType.ON_HEIGHT_CHANGE, - useCallback((values: OnHeightChangeMessage) => setFrameHeight?.(values.height), [setFrameHeight]) + useCallback((values: OnHeightChangeMessage) => { + setFrameHeight?.(values.height) + }, []) ) useEditorReceiveHandler( @@ -135,13 +142,13 @@ export const RenderIframe: React.FC = ({ rendererType } }) - setRendererStatus(true) + setRendererReady(true) }, [iframeCommunicator, rendererBaseUrl, rendererType]) ) useEffectOnRenderTypeChange(rendererType, onIframeLoad) - useSendDarkModeStatusToRenderer(forcedDarkMode) - useSendMarkdownToRenderer(markdownContentLines) + useSendDarkModeStatusToRenderer(forcedDarkMode, rendererReady) + useSendMarkdownToRenderer(markdownContentLines, rendererReady) useSendScrollState(scrollState) diff --git a/src/components/intro-page/hooks/use-intro-page-content.ts b/src/components/intro-page/hooks/use-intro-page-content.ts deleted file mode 100644 index 344dc9363..000000000 --- a/src/components/intro-page/hooks/use-intro-page-content.ts +++ /dev/null @@ -1,22 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file) - * - * SPDX-License-Identifier: AGPL-3.0-only - */ - -import { useEffect, useState } from 'react' -import { useTranslation } from 'react-i18next' -import { fetchFrontPageContent } from '../requests' - -export const useIntroPageContent = (): string[] | undefined => { - const { t } = useTranslation() - const [content, setContent] = useState(undefined) - - useEffect(() => { - fetchFrontPageContent() - .then((content) => setContent(content.split('\n'))) - .catch(() => setContent(undefined)) - }, [t]) - - return content -} diff --git a/src/components/intro-page/intro-custom-content.tsx b/src/components/intro-page/intro-custom-content.tsx index 5203e5bd0..e3243c89d 100644 --- a/src/components/intro-page/intro-custom-content.tsx +++ b/src/components/intro-page/intro-custom-content.tsx @@ -4,43 +4,34 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import React, { Fragment, useMemo } from 'react' -import { useIntroPageContent } from './hooks/use-intro-page-content' -import { useApplicationState } from '../../hooks/common/use-application-state' +import React, { useEffect, useState } from 'react' import { WaitSpinner } from '../common/wait-spinner/wait-spinner' import { RenderIframe } from '../editor-page/renderer-pane/render-iframe' import { RendererType } from '../render-page/window-post-message-communicator/rendering-message' +import { useTranslation } from 'react-i18next' +import { fetchFrontPageContent } from './requests' /** * Fetches the content for the customizable part of the intro page and renders it. */ export const IntroCustomContent: React.FC = () => { - const introPageContent = useIntroPageContent() - const rendererReady = useApplicationState((state) => state.rendererStatus.rendererReady) + const { t } = useTranslation() + const [content, setContent] = useState(undefined) - const spinner = useMemo(() => { - if (!rendererReady && introPageContent !== undefined) { - return - } - }, [introPageContent, rendererReady]) + useEffect(() => { + fetchFrontPageContent() + .then((content) => setContent(content.split('\n'))) + .catch(() => setContent(undefined)) + }, [t]) - const introContent = useMemo(() => { - if (introPageContent !== undefined) { - return ( - - ) - } - }, [introPageContent]) - - return ( - - {spinner} - {introContent} - + return content === undefined ? ( + + ) : ( + ) } diff --git a/src/components/render-page/window-post-message-communicator/hooks/use-effect-on-renderer-ready.ts b/src/components/render-page/window-post-message-communicator/hooks/use-effect-on-renderer-ready.ts deleted file mode 100644 index 98739db7e..000000000 --- a/src/components/render-page/window-post-message-communicator/hooks/use-effect-on-renderer-ready.ts +++ /dev/null @@ -1,23 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file) - * - * SPDX-License-Identifier: AGPL-3.0-only - */ - -import { useEffect } from 'react' -import { useApplicationState } from '../../../../hooks/common/use-application-state' - -/** - * Executes the given callback if it changes or the renderer is ready for receiving messages. - * - * @param sendOnReadyCallback The callback that should get executed. - */ -export const useEffectOnRendererReady = (sendOnReadyCallback: () => void): void => { - const rendererReady = useApplicationState((state) => state.rendererStatus.rendererReady) - - useEffect(() => { - if (rendererReady) { - sendOnReadyCallback() - } - }, [rendererReady, sendOnReadyCallback]) -} diff --git a/src/components/render-page/window-post-message-communicator/hooks/use-send-to-renderer.ts b/src/components/render-page/window-post-message-communicator/hooks/use-send-to-renderer.ts index 01f3a7e23..785a64275 100644 --- a/src/components/render-page/window-post-message-communicator/hooks/use-send-to-renderer.ts +++ b/src/components/render-page/window-post-message-communicator/hooks/use-send-to-renderer.ts @@ -4,27 +4,26 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import { useCallback } from 'react' +import { useEffect } from 'react' import type { CommunicationMessages, EditorToRendererMessageType } from '../rendering-message' import { useEditorToRendererCommunicator } from '../../../editor-page/render-context/editor-to-renderer-communicator-context-provider' import type { MessagePayload } from '../window-post-message-communicator' -import { useEffectOnRendererReady } from './use-effect-on-renderer-ready' /** * Sends the given message to the renderer. * * @param message The message to send + * @param rendererReady Defines if the target renderer is ready */ export const useSendToRenderer = ( - message: undefined | Extract> + message: undefined | Extract>, + rendererReady: boolean ): void => { const iframeCommunicator = useEditorToRendererCommunicator() - useEffectOnRendererReady( - useCallback(() => { - if (message) { - iframeCommunicator.sendMessageToOtherSide(message) - } - }, [iframeCommunicator, message]) - ) + useEffect(() => { + if (message && rendererReady) { + iframeCommunicator.sendMessageToOtherSide(message) + } + }, [iframeCommunicator, message, rendererReady]) } diff --git a/src/components/slide-show-page/slide-show-page-content.tsx b/src/components/slide-show-page/slide-show-page-content.tsx index 77362b012..2386099cf 100644 --- a/src/components/slide-show-page/slide-show-page-content.tsx +++ b/src/components/slide-show-page/slide-show-page-content.tsx @@ -15,6 +15,7 @@ import { useTranslation } from 'react-i18next' import { useTrimmedNoteMarkdownContentWithoutFrontmatter } from '../../hooks/common/use-trimmed-note-markdown-content-without-frontmatter' import { useSendToRenderer } from '../render-page/window-post-message-communicator/hooks/use-send-to-renderer' import { useApplicationState } from '../../hooks/common/use-application-state' +import { setRendererStatus } from '../../redux/renderer-status/methods' /** * Renders the current markdown content as a slideshow. @@ -24,6 +25,7 @@ export const SlideShowPageContent: React.FC = () => { useTranslation() const slideOptions = useApplicationState((state) => state.noteDetails.frontmatter.slideOptions) + const rendererReady = useApplicationState((state) => state.rendererStatus.rendererReady) useSendToRenderer( useMemo( () => ({ @@ -31,7 +33,8 @@ export const SlideShowPageContent: React.FC = () => { slideOptions }), [slideOptions] - ) + ), + rendererReady ) return ( @@ -41,6 +44,7 @@ export const SlideShowPageContent: React.FC = () => { markdownContentLines={markdownContentLines} rendererType={RendererType.SLIDESHOW} onFirstHeadingChange={updateNoteTitleByFirstHeading} + onRendererStatusChange={setRendererStatus} /> )