From f5569d74446803d7cdc12b5932b305e91ba1a56b Mon Sep 17 00:00:00 2001 From: ekzyis Date: Sun, 24 Nov 2024 01:37:30 +0100 Subject: [PATCH] Only fetch logs when we need them (#1638) * Don't fetch logs as anon * Only fetch logs if we need them on the current page * Wait for poll to finish with setTimeout This makes sure that we wait for the pending poll to finish before we poll again. This prevents running multiple polls at the same time on slow connections. I noticed we don't need to queue a new poll ourselves since a poll updates effect dependencies so we will cleanup and run the effect again anyway. * Fix polling via useEffect abuse --- components/use-interval.js | 10 ---------- components/wallet-logger.js | 39 ++++++++++++++++++++++++++++--------- 2 files changed, 30 insertions(+), 19 deletions(-) delete mode 100644 components/use-interval.js diff --git a/components/use-interval.js b/components/use-interval.js deleted file mode 100644 index 04b528ce..00000000 --- a/components/use-interval.js +++ /dev/null @@ -1,10 +0,0 @@ -import { useEffect } from 'react' - -function useInterval (cb, ms, deps) { - return useEffect(() => { - const interval = setInterval(cb, ms) - return () => clearInterval(interval) - }, deps) -} - -export default useInterval diff --git a/components/wallet-logger.js b/components/wallet-logger.js index 7beadeb0..c0b8bd0d 100644 --- a/components/wallet-logger.js +++ b/components/wallet-logger.js @@ -1,5 +1,5 @@ import LogMessage from './log-message' -import { useCallback, useMemo, useState } from 'react' +import { useCallback, useEffect, useMemo, useRef, useState } from 'react' import styles from '@/styles/log.module.css' import { Button } from 'react-bootstrap' import { useToast } from './toast' @@ -10,9 +10,9 @@ import { gql, useLazyQuery, useMutation } from '@apollo/client' import { useMe } from './me' import useIndexedDB, { getDbName } from './use-indexeddb' import { SSR } from '@/lib/constants' -import useInterval from './use-interval' import { decode as bolt11Decode } from 'bolt11' import { formatMsats } from '@/lib/format' +import { useRouter } from 'next/router' export function WalletLogs ({ wallet, embedded }) { const { logs, setLogs, hasMore, loadMore, loading } = useWalletLogs(wallet) @@ -204,6 +204,9 @@ export function useWalletLogs (wallet, initialPage = 1, logsPerPage = 10) { const [hasMore, setHasMore] = useState(true) const [cursor, setCursor] = useState(null) const [loading, setLoading] = useState(true) + const latestTimestamp = useRef() + const { me } = useMe() + const router = useRouter() const { getPage, error, notSupported } = useWalletLogDB() const [getWalletLogs] = useLazyQuery(WALLET_LOGS, SSR ? {} : { fetchPolicy: 'cache-and-network' }) @@ -214,6 +217,7 @@ export function useWalletLogs (wallet, initialPage = 1, logsPerPage = 10) { const newLogs = typeof action === 'function' ? action(logs) : action // make sure 'more' button is removed if logs were deleted if (newLogs.length === 0) setHasMore(false) + latestTimestamp.current = newLogs[0]?.ts }, [logs, _setLogs, setHasMore]) const loadLogsPage = useCallback(async (page, pageSize, walletDef, variables = {}) => { @@ -301,21 +305,38 @@ export function useWalletLogs (wallet, initialPage = 1, logsPerPage = 10) { }, [loadLogsPage, page, logsPerPage, wallet?.def, hasMore]) const loadNew = useCallback(async () => { - const newestTs = logs[0]?.ts - const variables = { from: newestTs?.toString(), to: null } + const latestTs = latestTimestamp.current + const variables = { from: latestTs?.toString(), to: null } const result = await loadLogsPage(1, logsPerPage, wallet?.def, variables) setLoading(false) _setLogs(prevLogs => uniqueSort([...result.data, ...prevLogs])) - if (!newestTs) { + if (!latestTs) { // we only want to update the more button if we didn't fetch new logs since it is about old logs. // we didn't fetch new logs if this is our first fetch (no newest timestamp available) setHasMore(result.hasMore) } - }, [logs, wallet?.def, loadLogsPage]) + }, [wallet?.def, loadLogsPage]) - useInterval(() => { - loadNew().catch(console.error) - }, 1_000, [loadNew]) + useEffect(() => { + // only fetch new logs if we are on a page that uses logs + const needLogs = router.asPath.startsWith('/settings/wallets') || router.asPath.startsWith('/wallet/logs') + if (!me || !needLogs) return + + let timeout + let stop = false + + const poll = async () => { + await loadNew().catch(console.error) + if (!stop) timeout = setTimeout(poll, 1_000) + } + + timeout = setTimeout(poll, 1_000) + + return () => { + stop = true + clearTimeout(timeout) + } + }, [me?.id, router.pathname, loadNew]) return { logs, hasMore: !loading && hasMore, loadMore, setLogs, loading } }