Skip to content

Commit 4e3d919

Browse files
authored
feat: prefetch transaction list on tokens screen (#2137)
# Prefetch Transaction Data for Improved Activity Tab Performance ## What changed (plus any additional context for devs) - Added a `prefetchInfiniteTransactionList` function that loads transaction data in the background - Implemented prefetching on the Tokens/balances screen to give the ListTransactions API a head start before users navigate to the Activity tab - The prefetch function checks if data already exists in the cache to avoid unnecessary API calls - Added proper type imports and store access for the prefetch function to work outside React components ## What to test - Navigate to the Tokens/balances screen and verify that transaction data is being prefetched - Check that navigating to the Activity tab feels faster since data is already loading - Verify that the prefetch function doesn't make duplicate API calls if data already exists - Test with different wallet addresses to ensure prefetching works correctly for all accounts - Confirm that the prefetch function properly handles testnet mode and enabled chain IDs <!-- start pr-codex --> --- ## PR-Codex overview This PR introduces a new feature to prefetch transaction data for a user's address when they are on the tokens/balances screen, enhancing performance by loading data in advance. ### Detailed summary - Added `prefetchInfiniteTransactionList` function to prefetch transactions based on the user's address. - Implemented `useEffect` in the `Tokens` component to call the prefetch function when `currentAddress` changes. - Enhanced error handling and caching logic in the prefetch function. > ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}` <!-- end pr-codex -->
1 parent 6c2f403 commit 4e3d919

2 files changed

Lines changed: 67 additions & 1 deletion

File tree

src/entries/popup/hooks/useInfiniteTransactionList.ts

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { useVirtualizer } from '@tanstack/react-virtual';
22
import { useCallback, useEffect, useMemo, useState } from 'react';
3+
import { Address } from 'viem';
34

45
import { queryClient } from '~/core/react-query';
56
import { shortcuts } from '~/core/references/shortcuts';
@@ -15,9 +16,10 @@ import {
1516
usePendingTransactionsStore,
1617
} from '~/core/state';
1718
import { useTestnetModeStore } from '~/core/state/currentSettings/testnetMode';
19+
import { useNetworkStore } from '~/core/state/networks/networks';
1820
import { useCustomNetworkTransactionsStore } from '~/core/state/transactions/customNetworkTransactions';
1921
import { RainbowTransaction } from '~/core/types/transactions';
20-
import { useSupportedChains } from '~/core/utils/chains';
22+
import { getSupportedChains, useSupportedChains } from '~/core/utils/chains';
2123
import { RainbowError, logger } from '~/logger';
2224

2325
import { useKeyboardShortcut } from './useKeyboardShortcut';
@@ -33,6 +35,61 @@ interface UseInfiniteTransactionListParams {
3335

3436
const stableEmptyPendingTransactionsArray: RainbowTransaction[] = [];
3537

38+
/**
39+
* Prefetch the first page of transactions for the given address.
40+
* Only prefetches if data doesn't already exist in cache.
41+
* Accesses currency and chain IDs from stores internally.
42+
*/
43+
export const prefetchInfiniteTransactionList = async ({
44+
address,
45+
}: {
46+
address: Address;
47+
}) => {
48+
if (!address) return;
49+
50+
// Access stores directly (not hooks, since this is not a React component)
51+
const { currentCurrency: currency } = useCurrentCurrencyStore.getState();
52+
const { testnetMode } = useTestnetModeStore.getState();
53+
const { enabledChainIds } = useNetworkStore.getState();
54+
55+
// Get supported chains based on testnet mode
56+
const supportedChains = getSupportedChains({ testnets: testnetMode });
57+
const userChainIds = Array.from(enabledChainIds);
58+
const supportedChainIds = supportedChains
59+
.map(({ id }) => id)
60+
.filter((id) => userChainIds.includes(id));
61+
62+
if (!supportedChainIds.length) return;
63+
64+
const queryKey = consolidatedTransactionsQueryKey({
65+
address,
66+
currency,
67+
userChainIds: supportedChainIds,
68+
});
69+
70+
try {
71+
// Check if data already exists in cache
72+
const cachedData = queryClient.getQueryData(queryKey);
73+
if (cachedData) {
74+
// Data already exists, skip prefetch
75+
return;
76+
}
77+
78+
// Prefetch the first page of transactions in the background
79+
await queryClient.prefetchInfiniteQuery({
80+
queryKey,
81+
queryFn: consolidatedTransactionsQueryFunction,
82+
getNextPageParam: (lastPage: { nextPage?: string }) => lastPage?.nextPage,
83+
initialPageParam: null as string | null,
84+
});
85+
} catch (error) {
86+
// Silently fail - we don't want to disrupt the UI if prefetch fails
87+
logger.error(new RainbowError('Failed to prefetch transaction list'), {
88+
message: error,
89+
});
90+
}
91+
};
92+
3693
export const useInfiniteTransactionList = ({
3794
getScrollElement,
3895
}: UseInfiniteTransactionListParams) => {

src/entries/popup/pages/home/Tokens.tsx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ import { CoinRow } from '~/entries/popup/components/CoinRow/CoinRow';
4646
import { Asterisks } from '../../components/Asterisks/Asterisks';
4747
import { CoinbaseIcon } from '../../components/CoinbaseIcon/CoinbaseIcon';
4848
import { QuickPromo } from '../../components/QuickPromo/QuickPromo';
49+
import { prefetchInfiniteTransactionList } from '../../hooks/useInfiniteTransactionList';
4950
import useKeyboardAnalytics from '../../hooks/useKeyboardAnalytics';
5051
import { useKeyboardShortcut } from '../../hooks/useKeyboardShortcut';
5152
import { useRainbowNavigate } from '../../hooks/useRainbowNavigate';
@@ -159,6 +160,14 @@ export function Tokens({ scrollY }: { scrollY: MotionValue<number> }) {
159160
},
160161
);
161162

163+
// Prefetch transactions when on the tokens/balances screen
164+
// This gives the slow ListTransactions API a headstart before user navigates to activity
165+
useEffect(() => {
166+
prefetchInfiniteTransactionList({
167+
address: currentAddress,
168+
});
169+
}, [currentAddress]);
170+
162171
const isPinned = useCallback(
163172
(assetUniqueId: string) =>
164173
!!pinnedStore[currentAddress]?.[assetUniqueId]?.pinned,

0 commit comments

Comments
 (0)