Skip to content

Commit

Permalink
fix(core): speed up navigation performance (#8794)
Browse files Browse the repository at this point in the history
add some memo...
  • Loading branch information
EYHN committed Nov 12, 2024
1 parent f4abe39 commit 17c247a
Show file tree
Hide file tree
Showing 6 changed files with 97 additions and 74 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { useLiveData, useService } from '@toeverything/infra';
import clsx from 'clsx';
import { selectAtom } from 'jotai/utils';
import type { MouseEventHandler } from 'react';
import { useCallback, useMemo, useState } from 'react';
import { memo, useCallback, useMemo, useState } from 'react';

import { CollectionListItem } from './collections/collection-list-item';
import { PageListItem } from './docs/page-list-item';
Expand Down Expand Up @@ -240,7 +240,7 @@ export const PageListItemRenderer = (item: ListItem) => {
);
};

export const CollectionListItemRenderer = (item: ListItem) => {
export const CollectionListItemRenderer = memo((item: ListItem) => {
const props = useAtomValue(listsPropsAtom);
const { selectionActive } = useAtomValue(selectionStateAtom);
const collection = item as CollectionMeta;
Expand All @@ -252,7 +252,9 @@ export const CollectionListItemRenderer = (item: ListItem) => {
})}
/>
);
};
});

CollectionListItemRenderer.displayName = 'CollectionListItemRenderer';

export const TagListItemRenderer = (item: ListItem) => {
const props = useAtomValue(listsPropsAtom);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { RadioGroup, type RadioItem } from '@affine/component';
import type { AllPageFilterOption } from '@affine/core/components/atoms';
import { allPageFilterSelectAtom } from '@affine/core/components/atoms';
import { useNavigateHelper } from '@affine/core/components/hooks/use-navigate-helper';
import { WorkbenchService } from '@affine/core/modules/workbench';
import { useI18n } from '@affine/i18n';
import { useService, WorkspaceService } from '@toeverything/infra';
import { useService } from '@toeverything/infra';
import { useAtom } from 'jotai';
import { useCallback, useEffect, useMemo, useState } from 'react';

Expand All @@ -14,26 +14,25 @@ export const WorkspaceModeFilterTab = ({
}: {
activeFilter: AllPageFilterOption;
}) => {
const workspace = useService(WorkspaceService).workspace;
const t = useI18n();
const [value, setValue] = useState(activeFilter);
const [filterMode, setFilterMode] = useAtom(allPageFilterSelectAtom);
const { jumpToCollections, jumpToTags, jumpToPage } = useNavigateHelper();
const workbenchService = useService(WorkbenchService);
const handleValueChange = useCallback(
(value: AllPageFilterOption) => {
switch (value) {
case 'collections':
jumpToCollections(workspace.id);
workbenchService.workbench.openCollections();
break;
case 'tags':
jumpToTags(workspace.id);
workbenchService.workbench.openTags();
break;
case 'docs':
jumpToPage(workspace.id, 'all');
workbenchService.workbench.openAll();
break;
}
},
[jumpToCollections, jumpToPage, jumpToTags, workspace]
[workbenchService.workbench]
);

useEffect(() => {
Expand Down
71 changes: 30 additions & 41 deletions packages/frontend/core/src/components/root-app-sidebar/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { useAsyncCallback } from '@affine/core/components/hooks/affine-async-hooks';
import {
AddPageButton,
AppDownloadButton,
Expand All @@ -23,7 +22,6 @@ import {
} from '@affine/core/modules/explorer';
import { ExplorerTags } from '@affine/core/modules/explorer/views/sections/tags';
import { CMDKQuickSearchService } from '@affine/core/modules/quicksearch/services/cmdk';
import { isNewTabTrigger } from '@affine/core/utils';
import { useI18n } from '@affine/i18n';
import { track } from '@affine/track';
import type { Doc } from '@blocksuite/affine/store';
Expand All @@ -35,17 +33,11 @@ import {
SettingsIcon,
} from '@blocksuite/icons/rc';
import type { Workspace } from '@toeverything/infra';
import {
useLiveData,
useService,
useServices,
WorkspaceService,
} from '@toeverything/infra';
import type { MouseEvent, ReactElement } from 'react';
import { useCallback } from 'react';
import { useLiveData, useService, useServices } from '@toeverything/infra';
import type { ReactElement } from 'react';
import { memo, useCallback } from 'react';

import { WorkbenchService } from '../../modules/workbench';
import { usePageHelper } from '../blocksuite/block-suite-page-list/utils';
import { WorkspaceNavigator } from '../workspace-selector';
import {
quickSearch,
Expand All @@ -72,42 +64,43 @@ export type RootAppSidebarProps = {
};
};

const AllDocsButton = () => {
const t = useI18n();
const { workbenchService } = useServices({
WorkbenchService,
});
const workbench = workbenchService.workbench;
const allPageActive = useLiveData(
workbench.location$.selector(location => location.pathname === '/all')
);

return (
<MenuLinkItem icon={<AllDocsIcon />} active={allPageActive} to={'/all'}>
<span data-testid="all-pages">
{t['com.affine.workspaceSubPath.all']()}
</span>
</MenuLinkItem>
);
};

/**
* This is for the whole affine app sidebar.
* This component wraps the app sidebar in `@affine/component` with logic and data.
*
*/
export const RootAppSidebar = (): ReactElement => {
const { workbenchService, workspaceService, cMDKQuickSearchService } =
useServices({
WorkspaceService,
WorkbenchService,
CMDKQuickSearchService,
});
const currentWorkspace = workspaceService.workspace;
export const RootAppSidebar = memo((): ReactElement => {
const { workbenchService, cMDKQuickSearchService } = useServices({
WorkbenchService,
CMDKQuickSearchService,
});
const t = useI18n();
const globalDialogService = useService(GlobalDialogService);
const workspaceDialogService = useService(WorkspaceDialogService);
const workbench = workbenchService.workbench;
const currentPath = useLiveData(
workbench.location$.map(location => location.pathname)
);
const onOpenQuickSearchModal = useCallback(() => {
cMDKQuickSearchService.toggle();
}, [cMDKQuickSearchService]);

const allPageActive = currentPath === '/all';

const pageHelper = usePageHelper(currentWorkspace.docCollection);

const onClickNewPage = useAsyncCallback(
async (e?: MouseEvent) => {
pageHelper.createPage(undefined, isNewTabTrigger(e) ? 'new-tab' : true);
track.$.navigationPanel.$.createDoc();
},
[pageHelper]
);

const onOpenSettingModal = useCallback(() => {
globalDialogService.open('setting', {
activeTab: 'appearance',
Expand Down Expand Up @@ -169,13 +162,9 @@ export const RootAppSidebar = (): ReactElement => {
data-event-props="$.navigationPanel.$.quickSearch"
onClick={onOpenQuickSearchModal}
/>
<AddPageButton onClick={onClickNewPage} />
<AddPageButton />
</div>
<MenuLinkItem icon={<AllDocsIcon />} active={allPageActive} to={'/all'}>
<span data-testid="all-pages">
{t['com.affine.workspaceSubPath.all']()}
</span>
</MenuLinkItem>
<AllDocsButton />
<AppSidebarJournalButton />
<MenuItem
data-testid="slider-bar-workspace-setting-button"
Expand Down Expand Up @@ -220,6 +209,6 @@ export const RootAppSidebar = (): ReactElement => {
</SidebarContainer>
</AppSidebar>
);
};
});

RootAppSidebar.displayName = 'memo(RootAppSidebar)';
Original file line number Diff line number Diff line change
@@ -1,24 +1,35 @@
import { IconButton } from '@affine/component';
import { usePageHelper } from '@affine/core/components/blocksuite/block-suite-page-list/utils';
import { isNewTabTrigger } from '@affine/core/utils';
import { useI18n } from '@affine/i18n';
import track from '@affine/track';
import { PlusIcon } from '@blocksuite/icons/rc';
import { useService, WorkspaceService } from '@toeverything/infra';
import clsx from 'clsx';
import type React from 'react';
import type { MouseEventHandler } from 'react';
import { type MouseEvent, useCallback } from 'react';

import * as styles from './index.css';

interface AddPageButtonProps {
onClick?: MouseEventHandler;
className?: string;
style?: React.CSSProperties;
}

const sideBottom = { side: 'bottom' as const };
export function AddPageButton({
onClick,
className,
style,
}: AddPageButtonProps) {
export function AddPageButton({ className, style }: AddPageButtonProps) {
const workspaceService = useService(WorkspaceService);
const currentWorkspace = workspaceService.workspace;
const pageHelper = usePageHelper(currentWorkspace.docCollection);

const onClickNewPage = useCallback(
(e?: MouseEvent) => {
pageHelper.createPage(undefined, isNewTabTrigger(e) ? 'new-tab' : true);
track.$.navigationPanel.$.createDoc();
},
[pageHelper]
);

const t = useI18n();

return (
Expand All @@ -28,8 +39,8 @@ export function AddPageButton({
data-testid="sidebar-new-page-button"
style={style}
className={clsx([styles.root, className])}
onClick={onClick}
onAuxClick={onClick}
onClick={onClickNewPage}
onAuxClick={onClickNewPage}
>
<PlusIcon />
</IconButton>
Expand Down
47 changes: 34 additions & 13 deletions packages/frontend/core/src/modules/explorer/views/tree/node.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,34 @@ interface WebExplorerTreeNodeProps extends BaseExplorerTreeNodeProps {
dropEffect?: ExplorerTreeNodeDropEffect;
}

/**
* specific rename modal for explorer tree node,
* Separate it into a separate component to prevent re-rendering the entire component when width changes.
*/
const ExplorerTreeNodeRenameModal = ({
setRenaming,
handleRename,
rawName,
}: {
setRenaming: (renaming: boolean) => void;
handleRename: (newName: string) => void;
rawName: string | undefined;
}) => {
const appSidebarService = useService(AppSidebarService).sidebar;
const sidebarWidth = useLiveData(appSidebarService.width$);
return (
<RenameModal
open
width={sidebarWidth - 32}
onOpenChange={setRenaming}
onRename={handleRename}
currentName={rawName ?? ''}
>
<div className={styles.itemRenameAnchor} />
</RenameModal>
);
};

export const ExplorerTreeNode = ({
children,
icon: Icon,
Expand Down Expand Up @@ -126,9 +154,6 @@ export const ExplorerTreeNode = ({
const [lastInGroup, setLastInGroup] = useState(false);
const rootRef = useRef<HTMLDivElement>(null);

const appSidebarService = useService(AppSidebarService).sidebar;
const sidebarWidth = useLiveData(appSidebarService.width$);

const { emoji, name } = useMemo(() => {
if (!extractEmojiAsIcon || !rawName) {
return {
Expand Down Expand Up @@ -379,16 +404,12 @@ export const ExplorerTreeNode = ({
</div>
</div>

{renameable && (
<RenameModal
open={!!renaming}
width={sidebarWidth - 32}
onOpenChange={setRenaming}
onRename={handleRename}
currentName={rawName ?? ''}
>
<div className={styles.itemRenameAnchor} />
</RenameModal>
{renameable && renaming && (
<ExplorerTreeNodeRenameModal
setRenaming={setRenaming}
handleRename={handleRename}
rawName={rawName}
/>
)}
</div>
);
Expand Down
1 change: 1 addition & 0 deletions packages/frontend/core/src/modules/workbench/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export { View as WorkbenchView } from './entities/view';
export { Workbench } from './entities/workbench';
export { ViewScope } from './scopes/view';
export { ViewService } from './services/view';
export { WorkbenchService } from './services/workbench';
export { useBindWorkbenchToBrowserRouter } from './view/browser-adapter';
export { useIsActiveView } from './view/use-is-active-view';
Expand Down

0 comments on commit 17c247a

Please sign in to comment.