Skip to content

Commit

Permalink
* merge div.p-4 with its child div.row
Browse files Browse the repository at this point in the history
- prop `nextCursorRoute` and `<RouteLink>` in favor of emitting `button@click` event
@ `<PageNextButton>`
* replace `p.h4` with `h4` @ `<PageCurrentButton>`
@ components/paginations

- prop `currentRoute` since `<PageNextButton>` no longer require prop `nextCursorRoute` returned from `useNextCursorRoute()`
* rename prop `isLoadingNewPage` with `isFetching`
+ prop `fetchNextPage` & `hasNextPage` for `<PageNextButton>`
@ `<PostPage>`
* replace class `h-5` with `fs-5` to remove its `margin-bottom` @ `renderers/list/<ReplyItem>`
@ components/Post

* passing `QueryFunctionContext.pageParam` to `queryFn()` as `queryParam.cursor` @ `useApiWithCursor()@api/index.ts`

* no longer passing cursor to ref `queryParam` in favor of `useApiWithCursor()@api/index.ts` @ `fetchPosts()`
- param `cursor` to inline its usage from callers @ `parseRouteThenFetch()`
* now will always invoke `parseRouteThenFetch()` no matter if the page with the cursor in route already exists
* now will scroll to the top when the route is totally different new query @ `onBeforeRouteUpdate()`
@ `views/<Post>`
@ fe
  • Loading branch information
n0099 committed Mar 8, 2024
1 parent 43520cc commit 2ed3aa0
Show file tree
Hide file tree
Showing 6 changed files with 32 additions and 40 deletions.
5 changes: 4 additions & 1 deletion fe/src/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,10 @@ const useApiWithCursor = <
QueryKey, Cursor
>({
queryKey: [endpoint, queryParam],
queryFn: async () => queryFn<TResponse & CursorPagination, TQueryParam>(`/${endpoint}`, queryParam?.value),
queryFn: async ({ pageParam }) => queryFn<TResponse & CursorPagination, TQueryParam & { cursor?: Cursor }>(
`/${endpoint}`,
{ ...queryParam?.value as TQueryParam, cursor: pageParam === '' ? undefined : pageParam }
),
initialPageParam: '',
getNextPageParam: lastPage => lastPage.pages.nextCursor,
enabled
Expand Down
18 changes: 10 additions & 8 deletions fe/src/components/Post/PostPage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,27 @@
<PageCurrentButton :currentCursor="props.posts.pages.currentCursor" />
<RendererList v-if="renderType === 'list'" :initialPosts="posts" />
<RendererTable v-else-if="renderType === 'table'" :posts="posts" />
<PageNextButton v-if="!isLoadingNewPage && isLastPageInPages && props.posts.pages.hasMore"
:nextCursorRoute="nextCursorRoute" />
<!-- eslint-disable vue/v-on-handler-style -->
<PageNextButton v-if="isLastPageInPages && !isFetching && hasNextPage"
@click="async () => await fetchNextPage()" />
<!-- eslint-enable vue/v-on-handler-style -->
</template>

<script setup lang="ts">
import RendererTable from './renderers/RendererTable.vue';
import RendererList from './renderers/list/RendererList.vue';
import { PageCurrentButton, PageNextButton, useNextCursorRoute } from '../paginations/usePaginationButtons';
import PageCurrentButton from '../paginations/PageCurrentButton.vue';
import PageNextButton from '../paginations/PageNextButton.vue';
import type { PostRenderer } from '@/views/Post.vue';
import type { ApiPosts } from '@/api/index.d';
import type { RouteLocationNormalized } from 'vue-router';
import type { InfiniteQueryObserverBaseResult } from '@tanstack/vue-query';
const props = defineProps<{
posts: ApiPosts['response'],
renderType: PostRenderer,
currentRoute: RouteLocationNormalized,
isLoadingNewPage: boolean,
isFetching: boolean,
fetchNextPage: InfiniteQueryObserverBaseResult['fetchNextPage'],
hasNextPage: boolean,
isLastPageInPages: boolean
}>();
const nextCursorRoute = useNextCursorRoute(props.currentRoute, props.posts.pages.nextCursor);
</script>
2 changes: 1 addition & 1 deletion fe/src/components/Post/renderers/list/ReplyItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<div :data-post-id="reply.pid" :id="reply.pid.toString()">
<div :ref="el => elementRefsStore.pushOrClear('<RendererList>.reply-title', el as Element | null)"
class="reply-title sticky-top card-header">
<div class="d-inline-flex gap-1 h5">
<div class="d-inline-flex gap-1 fs-5">
<span class="badge bg-secondary">{{ reply.floor }}楼</span>
<span v-if="reply.subReplyCount > 0" class="badge bg-info">
{{ reply.subReplyCount }}条<FontAwesomeIcon icon="comment-dots" />
Expand Down
2 changes: 1 addition & 1 deletion fe/src/components/paginations/PageCurrentButton.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<div class="col align-middle"><hr /></div>
<div class="w-auto">
<div class="p-2 badge bg-light text-dark">
<p class="h4">{{ cursorTemplate(currentCursor) }}</p>
<h4>{{ cursorTemplate(currentCursor) }}</h4>
</div>
</div>
<div class="col align-middle"><hr /></div>
Expand Down
19 changes: 6 additions & 13 deletions fe/src/components/paginations/PageNextButton.vue
Original file line number Diff line number Diff line change
@@ -1,20 +1,13 @@
<template>
<div class="p-4">
<div class="row align-items-center">
<div class="col"><hr /></div>
<div class="w-auto">
<RouterLink :to="nextCursorRoute" class="btn btn-secondary">
<span class="h4">下一页</span>
</RouterLink>
</div>
<div class="col"><hr /></div>
<div class="row align-items-center p-4">
<div class="col align-middle"><hr /></div>
<div class="w-auto">
<button @click="() => $emit('click')" class="btn btn-secondary fs-5">下一页</button>
</div>
<div class="col align-middle"><hr /></div>
</div>
</template>

<script setup lang="ts">
import type { RouteLocationRaw } from 'vue-router';
import { RouterLink } from 'vue-router';
defineProps<{ nextCursorRoute: RouteLocationRaw }>();
defineEmits<{ click: [] }>();
</script>
26 changes: 10 additions & 16 deletions fe/src/views/Post.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
<PostNav v-if="renderType === 'list'" :postPages="data.pages" />
<div class="post-page col mx-auto ps-0" :class="{ 'renderer-list': renderType === 'list' }">
<PostPage v-for="(page, pageIndex) in data.pages" :key="page.pages.currentCursor"
:renderType="renderType" :posts="page"
:currentRoute="lastFetchingRoute" :isLoadingNewPage="isFetching"
:posts="page" :renderType="renderType" :isFetching="isFetching"
:fetchNextPage="fetchNextPage" :hasNextPage="hasNextPage"
:isLastPageInPages="pageIndex === data.pages.length - 1" />
</div>
<div v-if="renderType === 'list'" class="col d-none d-xxl-block p-0" />
Expand Down Expand Up @@ -53,7 +53,7 @@ export type PostRenderer = 'list' | 'table';
const route = useRoute();
const queryParam = ref<ApiPosts['queryParam']>();
const shouldFetch = ref<boolean>(false);
const { data, error, isPending, isRefetching, isFetching, isFetchedAfterMount, dataUpdatedAt, errorUpdatedAt } =
const { data, error, isPending, isRefetching, isFetching, isFetchedAfterMount, dataUpdatedAt, errorUpdatedAt, fetchNextPage, hasNextPage } =
useApiPosts(queryParam, shouldFetch);
const selectedRenderTypes = ref<[PostRenderer]>(['list']);
const renderType = computed(() => selectedRenderTypes.value[0]);
Expand Down Expand Up @@ -82,10 +82,7 @@ useHead({
const fetchPosts = (queryParams: ObjUnknown[], cursor: Cursor) => {
const startTime = Date.now();
queryParam.value = {
query: JSON.stringify(queryParams),
cursor: cursor === '' ? undefined : cursor
};
queryParam.value = { query: JSON.stringify(queryParams) };
shouldFetch.value = true;
watchOnce(isFetchedAfterMount, value => {
if (value)
Expand Down Expand Up @@ -120,28 +117,25 @@ watch(isFetchedAfterMount, async () => {
}
});
const parseRouteThenFetch = async (newRoute: RouteLocationNormalized, cursor: Cursor) => {
const parseRouteThenFetch = async (newRoute: RouteLocationNormalized) => {
if (queryFormRef.value === undefined)
return;
const flattenParams = await queryFormRef.value.parseRouteToGetFlattenParams(newRoute);
if (flattenParams === false)
return;
lastFetchingRoute.value = newRoute;
fetchPosts(flattenParams, cursor);
fetchPosts(flattenParams, getRouteCursorParam(newRoute));
};
onBeforeRouteUpdate(async (to, from) => {
const isNewQuery = useTriggerRouteUpdateStore()
.isTriggeredBy('<QueryForm>@submit', { ...to, force: true })
|| compareRouteIsNewQuery(to, from);
const cursor = getRouteCursorParam(to);
if (isNewQuery || _.isEmpty(_.filter(
data.value?.pages,
i => i.pages.currentCursor === cursor
)))
await parseRouteThenFetch(to, cursor);
if (isNewQuery)
window.scrollTo({ top: 0 });
await parseRouteThenFetch(to);
});
onMounted(async () => {
await parseRouteThenFetch(route, getRouteCursorParam(route));
await parseRouteThenFetch(route);
});
</script>
Expand Down

0 comments on commit 2ed3aa0

Please sign in to comment.