From 66a626c91655e040cabc3e66708a3feb8e22813a Mon Sep 17 00:00:00 2001 From: Ryan Wang Date: Fri, 24 Feb 2023 12:10:13 +0800 Subject: [PATCH] refactor: use tanstack query to refactor post-related fetching (#879) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #### What type of PR is this? /kind improvement #### What this PR does / why we need it: 使用 [TanStack Query](https://github.com/TanStack/query) 重构文章相关数据请求的相关逻辑。 #### Which issue(s) this PR fixes: Ref https://github.com/halo-dev/halo/issues/3360 #### Special notes for your reviewer: 测试方式: 1. 测试文章相关联的页面,包括文章管理、分类、标签。 #### Does this PR introduce a user-facing change? ```release-note None ``` --- .../CategoryDropdownSelector.vue | 10 +- .../dropdown-selector/TagDropdownSelector.vue | 8 +- .../inputs/category-select/CategorySelect.vue | 21 +- .../components/CategoryTag.vue | 2 +- .../components/SearchResultListItem.vue | 2 +- src/formkit/inputs/tag-select/TagSelect.vue | 46 +- .../contents/posts/DeletedPostList.vue | 134 ++--- src/modules/contents/posts/PostList.vue | 489 ++++++++---------- .../posts/categories/CategoryList.vue | 10 +- .../composables/use-post-category.ts | 77 +-- .../contents/posts/categories/utils/index.ts | 2 +- src/modules/contents/posts/tags/TagList.vue | 14 +- .../posts/tags/composables/use-post-tag.ts | 74 +-- .../posts/widgets/RecentPublishedWidget.vue | 22 +- 14 files changed, 398 insertions(+), 513 deletions(-) diff --git a/src/components/dropdown-selector/CategoryDropdownSelector.vue b/src/components/dropdown-selector/CategoryDropdownSelector.vue index 3d5efb534..6de0f50fb 100644 --- a/src/components/dropdown-selector/CategoryDropdownSelector.vue +++ b/src/components/dropdown-selector/CategoryDropdownSelector.vue @@ -20,9 +20,7 @@ const emit = defineEmits<{ (event: "select", category?: Category): void; }>(); -const { categories, handleFetchCategories } = usePostCategory({ - fetchOnMounted: false, -}); +const { categories } = usePostCategory(); const handleSelect = (category: Category) => { if ( @@ -39,7 +37,6 @@ const handleSelect = (category: Category) => { }; function onDropdownShow() { - handleFetchCategories(); setTimeout(() => { setFocus("categoryDropdownSelectorInput"); }, 200); @@ -53,11 +50,14 @@ let fuse: Fuse | undefined = undefined; watch( () => categories.value, () => { - fuse = new Fuse(categories.value, { + fuse = new Fuse(categories.value || [], { keys: ["spec.displayName", "metadata.name"], useExtendedSearch: true, threshold: 0.2, }); + }, + { + immediate: true, } ); diff --git a/src/components/dropdown-selector/TagDropdownSelector.vue b/src/components/dropdown-selector/TagDropdownSelector.vue index 25983b141..e3d9742b9 100644 --- a/src/components/dropdown-selector/TagDropdownSelector.vue +++ b/src/components/dropdown-selector/TagDropdownSelector.vue @@ -21,7 +21,7 @@ const emit = defineEmits<{ (event: "select", tag?: Tag): void; }>(); -const { tags, handleFetchTags } = usePostTag({ fetchOnMounted: false }); +const { tags } = usePostTag(); const handleSelect = (tag: Tag) => { if (props.selected && tag.metadata.name === props.selected.metadata.name) { @@ -35,7 +35,6 @@ const handleSelect = (tag: Tag) => { }; function onDropdownShow() { - handleFetchTags(); setTimeout(() => { setFocus("tagDropdownSelectorInput"); }, 200); @@ -49,11 +48,14 @@ let fuse: Fuse | undefined = undefined; watch( () => tags.value, () => { - fuse = new Fuse(tags.value, { + fuse = new Fuse(tags.value || [], { keys: ["spec.displayName", "metadata.name", "spec.email"], useExtendedSearch: true, threshold: 0.2, }); + }, + { + immediate: true, } ); diff --git a/src/formkit/inputs/category-select/CategorySelect.vue b/src/formkit/inputs/category-select/CategorySelect.vue index e1baf5d09..88cabed6a 100644 --- a/src/formkit/inputs/category-select/CategorySelect.vue +++ b/src/formkit/inputs/category-select/CategorySelect.vue @@ -35,9 +35,7 @@ const multiple = computed(() => { return multiple === "true"; }); -const { categories, categoriesTree, handleFetchCategories } = usePostCategory({ - fetchOnMounted: true, -}); +const { categories, categoriesTree, handleFetchCategories } = usePostCategory(); provide>("categoriesTree", categoriesTree); @@ -69,7 +67,7 @@ const searchResults = computed(() => { watch( () => searchResults.value, (value) => { - if (value?.length > 0 && text.value) { + if (value?.length && text.value) { selectedCategory.value = value[0]; scrollToSelected(); } else { @@ -81,11 +79,14 @@ watch( watch( () => categories.value, () => { - fuse = new Fuse(categories.value, { + fuse = new Fuse(categories.value || [], { keys: ["spec.displayName", "spec.slug"], useExtendedSearch: true, threshold: 0.2, }); + }, + { + immediate: true, } ); @@ -94,14 +95,14 @@ const selectedCategories = computed(() => { const currentValue = props.context._value || []; return currentValue .map((categoryName): Category | undefined => { - return categories.value.find( + return categories.value?.find( (category) => category.metadata.name === categoryName ); }) .filter(Boolean) as Category[]; } - const category = categories.value.find( + const category = categories.value?.find( (category) => category.metadata.name === props.context._value ); return [category].filter(Boolean) as Category[]; @@ -140,6 +141,8 @@ const handleSelect = (category: CategoryTree | Category) => { }; const handleKeydown = (e: KeyboardEvent) => { + if (!searchResults.value) return; + if (e.key === "ArrowDown") { e.preventDefault(); @@ -217,7 +220,7 @@ const handleCreateCategory = async () => { description: "", cover: "", template: "", - priority: categories.value.length + 1, + priority: categories.value?.length || 0 + 1, children: [], }, apiVersion: "content.halo.run/v1alpha1", @@ -286,7 +289,7 @@ const handleDelete = () => {
  • diff --git a/src/formkit/inputs/category-select/components/CategoryTag.vue b/src/formkit/inputs/category-select/components/CategoryTag.vue index 37a19b40d..f8e02b53d 100644 --- a/src/formkit/inputs/category-select/components/CategoryTag.vue +++ b/src/formkit/inputs/category-select/components/CategoryTag.vue @@ -24,7 +24,7 @@ const label = computed(() => { props.category.metadata.name ); return categories - .map((category: CategoryTree) => category.spec.displayName) + ?.map((category: CategoryTree) => category.spec.displayName) .join(" / "); }); diff --git a/src/formkit/inputs/category-select/components/SearchResultListItem.vue b/src/formkit/inputs/category-select/components/SearchResultListItem.vue index 5e7c80c73..5cc7bab5e 100644 --- a/src/formkit/inputs/category-select/components/SearchResultListItem.vue +++ b/src/formkit/inputs/category-select/components/SearchResultListItem.vue @@ -33,7 +33,7 @@ const label = computed(() => { props.category.metadata.name ); return categories - .map((category: CategoryTree) => category.spec.displayName) + ?.map((category: CategoryTree) => category.spec.displayName) .join(" / "); }); diff --git a/src/formkit/inputs/tag-select/TagSelect.vue b/src/formkit/inputs/tag-select/TagSelect.vue index e62f38a18..8b2afe5d0 100644 --- a/src/formkit/inputs/tag-select/TagSelect.vue +++ b/src/formkit/inputs/tag-select/TagSelect.vue @@ -2,7 +2,7 @@ import { apiClient } from "@/utils/api-client"; import type { FormKitFrameworkContext } from "@formkit/core"; import type { Tag } from "@halo-dev/api-client"; -import { computed, onMounted, ref, watch, type PropType } from "vue"; +import { computed, ref, watch, type PropType } from "vue"; import PostTag from "@/modules/contents/posts/tags/components/PostTag.vue"; import { IconCheckboxCircle, @@ -13,6 +13,7 @@ import { onClickOutside } from "@vueuse/core"; import Fuse from "fuse.js"; import { usePermission } from "@/utils/permission"; import { slugify } from "transliteration"; +import { usePostTag } from "@/modules/contents/posts/tags/composables/use-post-tag"; const { currentUserHasPermission } = usePermission(); @@ -36,7 +37,6 @@ const multiple = computed(() => { return multiple === "true"; }); -const postTags = ref([] as Tag[]); const selectedTag = ref(); const dropdownVisible = ref(false); const text = ref(""); @@ -46,8 +46,9 @@ onClickOutside(wrapperRef, () => { dropdownVisible.value = false; }); -// search +const { tags: postTags, handleFetchTags } = usePostTag(); +// search let fuse: Fuse | undefined = undefined; const searchResults = computed(() => { @@ -61,7 +62,7 @@ const searchResults = computed(() => { watch( () => searchResults.value, (value) => { - if (value?.length > 0 && text.value) { + if (value?.length && text.value) { selectedTag.value = value[0]; scrollToSelected(); } else { @@ -70,32 +71,31 @@ watch( } ); -const handleFetchTags = async () => { - const { data } = await apiClient.extension.tag.listcontentHaloRunV1alpha1Tag({ - page: 0, - size: 0, - }); - - postTags.value = data.items; - - fuse = new Fuse(data.items, { - keys: ["spec.displayName", "spec.slug"], - useExtendedSearch: true, - threshold: 0.2, - }); -}; +watch( + () => postTags.value, + () => { + fuse = new Fuse(postTags.value || [], { + keys: ["spec.displayName", "metadata.name", "spec.email"], + useExtendedSearch: true, + threshold: 0.2, + }); + }, + { + immediate: true, + } +); const selectedTags = computed(() => { if (multiple.value) { const selectedTagNames = (props.context._value as string[]) || []; return selectedTagNames .map((tagName): Tag | undefined => { - return postTags.value.find((tag) => tag.metadata.name === tagName); + return postTags.value?.find((tag) => tag.metadata.name === tagName); }) .filter(Boolean) as Tag[]; } - const tag = postTags.value.find( + const tag = postTags.value?.find( (tag) => tag.metadata.name === props.context._value ); @@ -129,6 +129,8 @@ const handleSelect = (tag: Tag) => { }; const handleKeydown = (e: KeyboardEvent) => { + if (!searchResults.value) return; + if (e.key === "ArrowDown") { e.preventDefault(); @@ -234,8 +236,6 @@ const handleDelete = () => { props.context.node.input(""); } }; - -onMounted(handleFetchTags);