1
0
mirror of https://github.com/misskey-dev/misskey.git synced 2026-05-05 00:45:50 +02:00

fix(frontend): ページネーションの進行方向を指定できるように (#16433)

* fix(frontend): ページネーションの進行方向を指定できるように

* Update Changelog

* fix lint

* fix: directionをMkPaginationに移動

* fix

* fix

* fix

---------

Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>
This commit is contained in:
かっこかり
2025-08-22 19:34:20 +09:00
committed by GitHub
parent 4d215bde10
commit ade603ff7a
5 changed files with 86 additions and 19 deletions

View File

@@ -37,6 +37,7 @@ export interface IPaginator<T = unknown, _T = T & MisskeyEntity> {
fetchingOlder: Ref<boolean>;
fetchingNewer: Ref<boolean>;
canFetchOlder: Ref<boolean>;
canFetchNewer: Ref<boolean>;
canSearch: boolean;
error: Ref<boolean>;
computedParams: ComputedRef<Misskey.Endpoints[PaginatorCompatibleEndpointPaths]['req'] | null | undefined> | null;
@@ -77,6 +78,7 @@ export class Paginator<
public fetchingOlder = ref(false);
public fetchingNewer = ref(false);
public canFetchOlder = ref(false);
public canFetchNewer = ref(false);
public canSearch = false;
public error = ref(false);
private endpoint: Endpoint;
@@ -85,7 +87,12 @@ export class Paginator<
public computedParams: ComputedRef<E['req'] | null | undefined> | null;
public initialId: MisskeyEntity['id'] | null = null;
public initialDate: number | null = null;
// 初回読み込み時、initialIdを基準にそれより新しいものを取得するか古いものを取得するか
// newer: initialIdより新しいものを取得する
// older: initialIdより古いものを取得する (default)
public initialDirection: 'newer' | 'older';
private offsetMode: boolean;
public noPaging: boolean;
public searchQuery = ref<null | string>('');
@@ -116,6 +123,7 @@ export class Paginator<
initialId?: MisskeyEntity['id'];
initialDate?: number | null;
initialDirection?: 'newer' | 'older';
order?: 'newest' | 'oldest';
// 一部のAPIはさらに遡れる場合でもパフォーマンス上の理由でlimit以下の結果を返す場合があり、その場合はsafe、それ以外はlimitにすることを推奨
@@ -222,15 +230,15 @@ export class Paginator<
if (this.canFetchDetection === 'limit') {
if (apiRes.length < FIRST_FETCH_LIMIT) {
this.canFetchOlder.value = false;
(this.initialDirection === 'older' ? this.canFetchOlder : this.canFetchNewer).value = false;
} else {
this.canFetchOlder.value = true;
(this.initialDirection === 'older' ? this.canFetchOlder : this.canFetchNewer).value = true;
}
} else if (this.canFetchDetection === 'safe' || this.canFetchDetection == null) {
if (apiRes.length === 0 || this.noPaging) {
this.canFetchOlder.value = false;
(this.initialDirection === 'older' ? this.canFetchOlder : this.canFetchNewer).value = false;
} else {
this.canFetchOlder.value = true;
(this.initialDirection === 'older' ? this.canFetchOlder : this.canFetchNewer).value = true;
}
}
@@ -273,7 +281,11 @@ export class Paginator<
if (i === 10) item._shouldInsertAd_ = true;
}
this.pushItems(apiRes);
if (this.order.value === 'oldest') {
this.unshiftItems(apiRes.toReversed(), false);
} else {
this.pushItems(apiRes);
}
if (this.canFetchDetection === 'limit') {
if (apiRes.length < FIRST_FETCH_LIMIT) {
@@ -313,7 +325,11 @@ export class Paginator<
this.fetchingNewer.value = false;
if (apiRes == null || apiRes.length === 0) return; // これやらないと余計なre-renderが走る
if (apiRes == null || apiRes.length === 0) {
this.canFetchNewer.value = false;
// 余計なre-renderを防止するためここで終了
return;
}
if (options.toQueue) {
this.aheadQueue.unshift(...apiRes.toReversed());
@@ -325,9 +341,19 @@ export class Paginator<
if (this.order.value === 'oldest') {
this.pushItems(apiRes);
} else {
this.unshiftItems(apiRes.toReversed());
this.unshiftItems(apiRes.toReversed(), false);
}
}
if (this.canFetchDetection === 'limit') {
if (apiRes.length < FIRST_FETCH_LIMIT) {
this.canFetchNewer.value = false;
} else {
this.canFetchNewer.value = true;
}
}
// canFetchDetectionが'safe'の場合・apiRes.length === 0 の場合は apiRes.length === 0 の場合に canFetchNewer.value = false になるが、
// 余計な re-render を防ぐために上部で処理している。そのため、ここでは何もしない
}
public trim(trigger = true): void {
@@ -336,10 +362,10 @@ export class Paginator<
if (this.useShallowRef && trigger) triggerRef(this.items);
}
public unshiftItems(newItems: T[]): void {
public unshiftItems(newItems: T[], trim = true): void {
if (newItems.length === 0) return; // これやらないと余計なre-renderが走る
this.items.value.unshift(...newItems.filter(x => !this.items.value.some(y => y.id === x.id))); // ストリーミングやポーリングのタイミングによっては重複することがあるため
this.trim(false);
if (trim) this.trim(true);
if (this.useShallowRef) triggerRef(this.items);
}