From 4468d2974025e10454522699b03ea8b99dfda74e Mon Sep 17 00:00:00 2001 From: Tom Moor Date: Tue, 1 Mar 2022 21:51:51 -0800 Subject: [PATCH] perf: Navigation of shared trees feels slow (#3171) * perf: Navigation of shared trees feels slow * remove redundant call to setActiveDocument Co-authored-by: Nan Yu --- app/components/Sidebar/Shared.tsx | 3 +- .../Sidebar/components/SharedDocumentLink.tsx | 16 ++++-- app/scenes/Document/Shared.tsx | 51 ++++++++++++++++--- app/stores/UiStore.ts | 8 ++- 4 files changed, 67 insertions(+), 11 deletions(-) diff --git a/app/components/Sidebar/Shared.tsx b/app/components/Sidebar/Shared.tsx index 0fcbc86f9..adfeab23c 100644 --- a/app/components/Sidebar/Shared.tsx +++ b/app/components/Sidebar/Shared.tsx @@ -14,7 +14,7 @@ type Props = { }; function SharedSidebar({ rootNode, shareId }: Props) { - const { documents } = useStores(); + const { ui, documents } = useStores(); return ( @@ -25,6 +25,7 @@ function SharedSidebar({ rootNode, shareId }: Props) { shareId={shareId} depth={1} node={rootNode} + activeDocumentId={ui.activeDocumentId} activeDocument={documents.active} /> diff --git a/app/components/Sidebar/components/SharedDocumentLink.tsx b/app/components/Sidebar/components/SharedDocumentLink.tsx index fd1b88e1e..90c7d6bb6 100644 --- a/app/components/Sidebar/components/SharedDocumentLink.tsx +++ b/app/components/Sidebar/components/SharedDocumentLink.tsx @@ -11,7 +11,8 @@ import SidebarLink from "./SidebarLink"; type Props = { node: NavigationNode; collection?: Collection; - activeDocument: Document | null | undefined; + activeDocumentId: string | undefined; + activeDocument: Document | undefined; isDraft?: boolean; depth: number; index: number; @@ -20,13 +21,21 @@ type Props = { }; function DocumentLink( - { node, collection, activeDocument, isDraft, depth, shareId }: Props, + { + node, + collection, + activeDocument, + activeDocumentId, + isDraft, + depth, + shareId, + }: Props, ref: React.RefObject ) { const { documents } = useStores(); const { t } = useTranslation(); - const isActiveDocument = activeDocument && activeDocument.id === node.id; + const isActiveDocument = activeDocumentId === node.id; const hasChildDocuments = !!node.children.length || activeDocument?.parentDocumentId === node.id; @@ -112,6 +121,7 @@ function DocumentLink( key={childNode.id} collection={collection} node={childNode} + activeDocumentId={activeDocumentId} activeDocument={activeDocument} isDraft={childNode.isDraft} depth={depth + 1} diff --git a/app/scenes/Document/Shared.tsx b/app/scenes/Document/Shared.tsx index 61bd6f25f..f09717bde 100644 --- a/app/scenes/Document/Shared.tsx +++ b/app/scenes/Document/Shared.tsx @@ -16,6 +16,11 @@ import Loading from "./components/Loading"; const EMPTY_OBJECT = {}; +type Response = { + document: DocumentModel; + sharedTree?: NavigationNode | undefined; +}; + type Props = RouteComponentProps<{ shareId: string; documentSlug: string; @@ -23,23 +28,58 @@ type Props = RouteComponentProps<{ location: Location<{ title?: string }>; }; +/** + * Find the document UUID from the slug given the sharedTree + * + * @param documentSlug The slug from the url + * @param response The response payload from the server + * @returns The document UUID, if found. + */ +function useDocumentId(documentSlug: string, response?: Response) { + let documentId; + + function findInTree(node: NavigationNode) { + if (node.url.endsWith(documentSlug)) { + documentId = node.id; + return true; + } + if (node.children) { + for (const child of node.children) { + if (findInTree(child)) { + return true; + } + } + } + return false; + } + + if (response?.sharedTree) { + findInTree(response.sharedTree); + } + + return documentId; +} + function SharedDocumentScene(props: Props) { const { ui } = useStores(); - const theme = useTheme(); - const [response, setResponse] = React.useState<{ - document: DocumentModel; - sharedTree?: NavigationNode | undefined; - }>(); + const [response, setResponse] = React.useState(); const [error, setError] = React.useState(); const { documents } = useStores(); const { shareId, documentSlug } = props.match.params; + const documentId = useDocumentId(documentSlug, response); // ensure the wider page color always matches the theme React.useEffect(() => { window.document.body.style.background = theme.background; }, [theme]); + React.useEffect(() => { + if (documentId) { + ui.setActiveDocument(documentId); + } + }, [ui, documentId]); + React.useEffect(() => { async function fetchData() { try { @@ -47,7 +87,6 @@ function SharedDocumentScene(props: Props) { shareId, }); setResponse(response); - ui.setActiveDocument(response.document); } catch (err) { setError(err); } diff --git a/app/stores/UiStore.ts b/app/stores/UiStore.ts index 9cb3307a6..b93a7d86c 100644 --- a/app/stores/UiStore.ts +++ b/app/stores/UiStore.ts @@ -124,7 +124,13 @@ class UiStore { }; @action - setActiveDocument = (document: Document): void => { + setActiveDocument = (document: Document | string): void => { + if (typeof document === "string") { + this.activeDocumentId = document; + this.observingUserId = undefined; + return; + } + this.activeDocumentId = document.id; this.observingUserId = undefined;