Rework state management to avoid rendering multiple while navigating between pages

Closes #5184

Signed-off-by: Oliver Sand <oliver.sand@sda-se.com>
This commit is contained in:
Oliver Sand
2021-04-26 16:53:28 +02:00
parent 35e32bbf4c
commit 17915e29b3
4 changed files with 81 additions and 22 deletions
@@ -0,0 +1,5 @@
---
'@backstage/plugin-techdocs': patch
---
Rework state management to avoid rendering multiple while navigating between pages.
@@ -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,
@@ -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 (
<Page themeId="documentation">
@@ -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<RawPage> & {
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]);
}