diff --git a/packages/frontend/core/src/modules/explorer/views/nodes/tag/index.tsx b/packages/frontend/core/src/modules/explorer/views/nodes/tag/index.tsx
index 3da8ecac13..3afa6c5ff8 100644
--- a/packages/frontend/core/src/modules/explorer/views/nodes/tag/index.tsx
+++ b/packages/frontend/core/src/modules/explorer/views/nodes/tag/index.tsx
@@ -3,6 +3,7 @@ import {
type DropTargetOptions,
toast,
} from '@affine/component';
+import type { Tag } from '@affine/core/modules/tag';
import { TagService } from '@affine/core/modules/tag';
import type { AffineDNDData } from '@affine/core/types/dnd';
import { useI18n } from '@affine/i18n';
@@ -46,7 +47,6 @@ export const ExplorerTagNode = ({
const tagRecord = useLiveData(tagService.tagList.tagByTagId$(tagId));
const tagColor = useLiveData(tagRecord?.color$);
const tagName = useLiveData(tagRecord?.value$);
- const tagDocIds = useLiveData(tagRecord?.pageIds$);
const Icon = useCallback(
({ className }: { className?: string }) => {
@@ -181,16 +181,27 @@ export const ExplorerTagNode = ({
dropEffect={handleDropEffectOnTag}
data-testid={`explorer-tag-${tagId}`}
>
- {tagDocIds?.map(docId => (
-
- ))}
+
);
};
+
+/**
+ * the `tag.pageIds$` has a performance issue,
+ * so we split the tag node children into a separate component,
+ * so it won't be rendered when the tag node is collapsed.
+ */
+export const ExplorerTagNodeDocs = ({ tag }: { tag: Tag }) => {
+ const tagDocIds = useLiveData(tag.pageIds$);
+
+ return tagDocIds.map(docId => (
+
+ ));
+};
diff --git a/packages/frontend/core/src/modules/tag/entities/tag-list.ts b/packages/frontend/core/src/modules/tag/entities/tag-list.ts
index 8edae7d2c5..efc5f473ff 100644
--- a/packages/frontend/core/src/modules/tag/entities/tag-list.ts
+++ b/packages/frontend/core/src/modules/tag/entities/tag-list.ts
@@ -12,8 +12,18 @@ export class TagList extends Entity {
super();
}
+ private readonly pool = new Map();
+
readonly tags$ = LiveData.from(this.store.watchTagIds(), []).map(ids => {
- return ids.map(id => this.framework.createEntity(Tag, { id }));
+ return ids.map(id => {
+ const exists = this.pool.get(id);
+ if (exists) {
+ return exists;
+ }
+ const record = this.framework.createEntity(Tag, { id });
+ this.pool.set(id, record);
+ return record;
+ });
});
createTag(value: string, color: string) {
diff --git a/packages/frontend/core/src/modules/tag/entities/tag.ts b/packages/frontend/core/src/modules/tag/entities/tag.ts
index 0d5018a516..f963fa59b7 100644
--- a/packages/frontend/core/src/modules/tag/entities/tag.ts
+++ b/packages/frontend/core/src/modules/tag/entities/tag.ts
@@ -62,6 +62,10 @@ export class Tag extends Entity<{ id: string }> {
});
}
+ /**
+ * @deprecated performance issue here, use with caution until it is fixed
+ * @fixme(EYHN): page.meta$ has performance issue
+ */
readonly pageIds$ = LiveData.computed(get => {
const pages = get(this.docs.list.docs$);
return pages