Reduce account overfetching when displaying collection lists (#39220)

This commit is contained in:
diondiondion 2026-05-29 17:27:57 +02:00 committed by GitHub
parent 8e15e49e87
commit 0caf334891
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 48 additions and 5 deletions

View File

@ -3,6 +3,7 @@ import { createAction } from '@reduxjs/toolkit';
import {
apiRemoveAccountFromFollowers,
apiGetEndorsedAccounts,
apiGetAccounts,
} from 'mastodon/api/accounts';
import type { ApiRelationshipJSON } from 'mastodon/api_types/relationships';
import { createDataLoadingThunk } from 'mastodon/store/typed_functions';
@ -113,3 +114,12 @@ export const fetchEndorsedAccounts = createDataLoadingThunk(
return data;
},
);
export const fetchAccounts = createDataLoadingThunk(
'accounts/multi_accounts',
({ accountIds }: { accountIds: string[] }) => apiGetAccounts(accountIds),
(data, { dispatch }) => {
dispatch(importFetchedAccounts(data));
return data;
},
);

View File

@ -19,6 +19,11 @@ import type {
ApiProfileUpdateParams,
} from '../api_types/profile';
export const apiGetAccounts = (ids: string[]) =>
apiRequestGet<ApiAccountJSON[]>('v1/accounts', {
id: ids,
});
export const apiSubmitAccountNote = (id: string, value: string) =>
apiRequestPost<ApiRelationshipJSON>(`v1/accounts/${id}/note`, {
comment: value,

View File

@ -15,7 +15,7 @@ export const apiUpdate = (list: Partial<ApiListJSON>) =>
export const apiGetLists = () => apiRequestGet<ApiListJSON[]>('v1/lists');
export const apiGetAccounts = (listId: string) =>
export const apiGetListAccounts = (listId: string) =>
apiRequestGet<ApiAccountJSON[]>(`v1/lists/${listId}/accounts`, {
limit: 0,
});

View File

@ -15,7 +15,7 @@ import { fetchList } from 'mastodon/actions/lists';
import { openModal } from 'mastodon/actions/modal';
import { apiFollowAccount } from 'mastodon/api/accounts';
import {
apiGetAccounts,
apiGetListAccounts,
apiAddAccountToList,
apiRemoveAccountFromList,
} from 'mastodon/api/lists';
@ -184,7 +184,7 @@ const ListMembers: React.FC<{
if (id) {
dispatch(fetchList(id));
void apiGetAccounts(id)
void apiGetListAccounts(id)
.then((data) => {
dispatch(importFetchedAccounts(data));
setAccountIds(data.map((a) => a.id));

View File

@ -12,7 +12,7 @@ import ChevronRightIcon from '@/material-icons/400-24px/chevron_right.svg?react'
import ListAltIcon from '@/material-icons/400-24px/list_alt.svg?react';
import { fetchList } from 'mastodon/actions/lists';
import { createList, updateList } from 'mastodon/actions/lists_typed';
import { apiGetAccounts } from 'mastodon/api/lists';
import { apiGetListAccounts } from 'mastodon/api/lists';
import type { ApiAccountJSON } from 'mastodon/api_types/accounts';
import type { RepliesPolicyType } from 'mastodon/api_types/lists';
import { Avatar } from 'mastodon/components/avatar';
@ -44,7 +44,7 @@ const MembersLink: React.FC<{
const [avatarAccounts, setAvatarAccounts] = useState<ApiAccountJSON[]>([]);
useEffect(() => {
void apiGetAccounts(id)
void apiGetListAccounts(id)
.then((data) => {
setAvatarCount(data.length);
setAvatarAccounts(data.slice(0, 3));

View File

@ -1,6 +1,7 @@
import type { PayloadAction } from '@reduxjs/toolkit';
import { createSlice } from '@reduxjs/toolkit';
import { fetchAccounts } from '@/mastodon/actions/accounts_typed';
import { importFetchedAccounts } from '@/mastodon/actions/importer';
import {
apiCreateCollection,
@ -20,6 +21,7 @@ import type {
CollectionAccountItem,
} from '@/mastodon/api_types/collections';
import { initialState, me } from '@/mastodon/initial_state';
import type { AppDispatch } from '@/mastodon/store';
import {
createAppAsyncThunk,
createAppSelector,
@ -322,16 +324,42 @@ const collectionSlice = createSlice({
},
});
/**
* Prefetch accounts whose avatars will be displayed in the collection list
*/
async function importAccountsForPreviewCard(
collections: ApiCollectionJSON[],
dispatch: AppDispatch,
) {
const previewAccountIds = collections
.flatMap((collection) =>
collection.items.slice(0, 3).map((item) => item.account_id),
)
.filter((id): id is string => !!id);
await dispatch(
fetchAccounts({
accountIds: previewAccountIds,
}),
);
}
export const fetchCollectionsCreatedByAccount = createDataLoadingThunk(
`${collectionSlice.name}/fetchCollectionsCreatedByAccount`,
({ accountId }: { accountId: string }) =>
apiGetCollectionsCreatedByAccount(accountId),
async ({ collections }, { dispatch }) => {
await importAccountsForPreviewCard(collections, dispatch);
},
);
export const fetchCollectionsFeaturingAccount = createDataLoadingThunk(
`${collectionSlice.name}/fetchCollectionsFeaturingAccount`,
({ accountId }: { accountId: string }) =>
apiGetCollectionsFeaturingAccount(accountId),
async ({ collections }, { dispatch }) => {
await importAccountsForPreviewCard(collections, dispatch);
},
);
export const fetchCollection = createDataLoadingThunk(