From 17915e29b31acb6ebfbacee71db655888ae5602e Mon Sep 17 00:00:00 2001 From: Oliver Sand Date: Mon, 26 Apr 2021 16:53:28 +0200 Subject: [PATCH] Rework state management to avoid rendering multiple while navigating between pages Closes #5184 Signed-off-by: Oliver Sand --- .changeset/techdocs-young-walls-decide.md | 5 ++ .../techdocs/src/reader/components/Reader.tsx | 38 ++++++------- .../src/reader/components/TechDocsPage.tsx | 6 +-- .../src/reader/components/useRawPage.ts | 54 +++++++++++++++++++ 4 files changed, 81 insertions(+), 22 deletions(-) create mode 100644 .changeset/techdocs-young-walls-decide.md create mode 100644 plugins/techdocs/src/reader/components/useRawPage.ts diff --git a/.changeset/techdocs-young-walls-decide.md b/.changeset/techdocs-young-walls-decide.md new file mode 100644 index 0000000000..8dc0373234 --- /dev/null +++ b/.changeset/techdocs-young-walls-decide.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-techdocs': patch +--- + +Rework state management to avoid rendering multiple while navigating between pages. diff --git a/plugins/techdocs/src/reader/components/Reader.tsx b/plugins/techdocs/src/reader/components/Reader.tsx index ff4f47dca0..6e5e0b5920 100644 --- a/plugins/techdocs/src/reader/components/Reader.tsx +++ b/plugins/techdocs/src/reader/components/Reader.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ import { EntityName } from '@backstage/catalog-model'; -import { useApi, configApiRef } from '@backstage/core'; +import { configApiRef, useApi } from '@backstage/core'; import { BackstageTheme } from '@backstage/theme'; import { useTheme } from '@material-ui/core'; import { Alert } from '@material-ui/lab'; @@ -24,6 +24,7 @@ import { useAsync } from 'react-use'; import { techdocsStorageApiRef } from '../../api'; import transformer, { addBaseUrl, + addGitFeedbackLink, addLinkClickListener, injectCss, onCssReady, @@ -31,10 +32,10 @@ import transformer, { rewriteDocLinks, sanitizeDOM, simplifyMkdocsFooter, - addGitFeedbackLink, } from '../transformers'; import { TechDocsNotFound } from './TechDocsNotFound'; import TechDocsProgressBar from './TechDocsProgressBar'; +import { useRawPage } from './useRawPage'; type Props = { entityId: EntityName; @@ -69,20 +70,20 @@ export const Reader = ({ entityId, onReady }: Props) => { }); } return techdocsStorageApi.syncEntityDocs({ kind, namespace, name }); - }); + }, [techdocsStorageApi, kind, namespace, name]); const { value: rawPage, loading: docLoading, error: docLoadError, - } = useAsync(async () => { - // do not automatically load same page again if URL has not changed, - // happens when generating new docs finishes - if (newerDocsExist && path === loadedPath) { - return null; + retry, + } = useRawPage(path, kind, namespace, name); + + useEffect(() => { + if (isSynced && newerDocsExist && path !== loadedPath) { + retry(); } - return techdocsStorageApi.getEntityDocs({ kind, namespace, name }, path); - }, [techdocsStorageApi, kind, namespace, name, path, isSynced]); + }); useEffect(() => { const updateSidebarPosition = () => { @@ -134,12 +135,12 @@ export const Reader = ({ entityId, onReady }: Props) => { onReady(); } // Pre-render - const transformedElement = transformer(rawPage as string, [ + const transformedElement = transformer(rawPage.content, [ sanitizeDOM(), addBaseUrl({ techdocsStorageApi, - entityId: entityId, - path, + entityId: rawPage.entityId, + path: rawPage.path, }), rewriteDocLinks(), removeMkdocsHeader(), @@ -304,16 +305,15 @@ export const Reader = ({ entityId, onReady }: Props) => { ]); }, [ rawPage, - entityId, navigate, onReady, shadowDomRef, - path, techdocsStorageApi, - theme, - kind, - namespace, - name, + theme.typography.fontFamily, + theme.palette.text.primary, + theme.palette.primary.main, + theme.palette.background.paper, + theme.palette.background.default, newerDocsExist, isSynced, configApi, diff --git a/plugins/techdocs/src/reader/components/TechDocsPage.tsx b/plugins/techdocs/src/reader/components/TechDocsPage.tsx index c15f3a6a44..338088be4d 100644 --- a/plugins/techdocs/src/reader/components/TechDocsPage.tsx +++ b/plugins/techdocs/src/reader/components/TechDocsPage.tsx @@ -15,7 +15,7 @@ */ import { Content, Page, useApi } from '@backstage/core'; -import React, { useState } from 'react'; +import React, { useCallback, useState } from 'react'; import { useParams } from 'react-router-dom'; import { useAsync } from 'react-use'; import { techdocsApiRef } from '../../api'; @@ -40,9 +40,9 @@ export const TechDocsPage = () => { return techdocsApi.getEntityMetadata({ kind, namespace, name }); }, [kind, namespace, name, techdocsApi]); - const onReady = () => { + const onReady = useCallback(() => { setDocumentReady(true); - }; + }, [setDocumentReady]); return ( diff --git a/plugins/techdocs/src/reader/components/useRawPage.ts b/plugins/techdocs/src/reader/components/useRawPage.ts new file mode 100644 index 0000000000..1bc23d2a45 --- /dev/null +++ b/plugins/techdocs/src/reader/components/useRawPage.ts @@ -0,0 +1,54 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { EntityName } from '@backstage/catalog-model'; +import { useApi } from '@backstage/core'; +import { useAsyncRetry } from 'react-use'; +import { AsyncState } from 'react-use/lib/useAsync'; +import { techdocsStorageApiRef } from '../../api'; + +export type RawPage = { + content: string; + path: string; + entityId: EntityName; +}; + +export function useRawPage( + path: string, + kind: string, + namespace: string, + name: string, +): AsyncState & { + retry(): void; +} { + const techdocsStorageApi = useApi(techdocsStorageApiRef); + + return useAsyncRetry(async () => { + const content = await techdocsStorageApi.getEntityDocs( + { kind, namespace, name }, + path, + ); + + return { + content, + path, + entityId: { + kind, + name, + namespace, + }, + }; + }, [techdocsStorageApi, kind, namespace, name, path]); +}