fix: stabilize useAccounts with combine and add cycle detection in useThread
- useAccounts: Replace unstable useMemo([queries]) with TanStack Query's combine option, which applies structural sharing (replaceEqualDeep) to the combined result. This prevents the accounts array from being a new reference on every render, breaking the cascade of unnecessary re-renders through useStatusQuery → useStatus → all Status components. - useThread: Add cycle detection (visited set) to the linear mode's while loop that traverses inReplyTos to find the root parent. Without this, circular reply chains (e.g. self-replies or A→B→A) would cause an infinite loop that freezes the browser tab. Co-authored-by: mkljczk <21127288+mkljczk@users.noreply.github.com>
This commit is contained in:
@ -1,5 +1,4 @@
|
||||
import { useQueries, useQueryClient } from '@tanstack/react-query';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import { useClient } from '@/hooks/use-client';
|
||||
import { queryKeys } from '@/queries/keys';
|
||||
@ -10,7 +9,7 @@ const useAccounts = (accountIds: Array<string>) => {
|
||||
const client = useClient();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const queries = useQueries({
|
||||
return useQueries({
|
||||
queries: accountIds.map((accountId) => ({
|
||||
queryKey: queryKeys.accounts.show(accountId),
|
||||
queryFn: async () => {
|
||||
@ -23,18 +22,12 @@ const useAccounts = (accountIds: Array<string>) => {
|
||||
},
|
||||
enabled: !!accountId,
|
||||
})),
|
||||
combine: (results) => ({
|
||||
data: results.map((result) => result.data).filter((account): account is Account => !!account),
|
||||
isLoading: results.some((result) => result.isLoading),
|
||||
isFetching: results.some((result) => result.isFetching),
|
||||
}),
|
||||
});
|
||||
|
||||
const accounts = useMemo(
|
||||
() => queries.map((query) => query.data).filter((account): account is Account => !!account),
|
||||
[queries],
|
||||
);
|
||||
|
||||
return {
|
||||
data: accounts,
|
||||
isLoading: queries.some((query) => query.isLoading),
|
||||
isFetching: queries.some((query) => query.isFetching),
|
||||
};
|
||||
};
|
||||
|
||||
export { useAccounts };
|
||||
|
||||
@ -265,9 +265,13 @@ const useThread = (statusId?: string, linear?: boolean) => {
|
||||
|
||||
if (linear) {
|
||||
let parentStatus: string = statusId;
|
||||
const visited = new Set<string>([parentStatus]);
|
||||
|
||||
while (inReplyTos[parentStatus]) {
|
||||
parentStatus = inReplyTos[parentStatus];
|
||||
const next = inReplyTos[parentStatus];
|
||||
if (visited.has(next)) break;
|
||||
visited.add(next);
|
||||
parentStatus = next;
|
||||
}
|
||||
|
||||
const threadStatuses = [parentStatus];
|
||||
|
||||
Reference in New Issue
Block a user