From 4406e53121efeb362e68609fe21768dad34a4dc1 Mon Sep 17 00:00:00 2001 From: Marshall Polaris Date: Thu, 1 Sep 2022 19:38:09 -0700 Subject: [PATCH] Make prefetching correctly use context cache (#835) --- web/components/following-button.tsx | 13 ++----- web/components/referrals-button.tsx | 6 +-- web/hooks/use-contracts.ts | 13 ++++--- web/hooks/use-portfolio-history.ts | 15 +++++--- web/hooks/use-prefetch.ts | 15 ++++---- web/hooks/use-user-bets.ts | 11 +++--- web/hooks/use-user.ts | 15 ++++---- web/lib/firebase/bets.ts | 38 +++++++------------ web/lib/firebase/contracts.ts | 4 ++ web/lib/firebase/users.ts | 4 ++ .../api/v0/user/[username]/bets/index.ts | 5 ++- 11 files changed, 68 insertions(+), 71 deletions(-) diff --git a/web/components/following-button.tsx b/web/components/following-button.tsx index c9aecbff..fdf739a1 100644 --- a/web/components/following-button.tsx +++ b/web/components/following-button.tsx @@ -2,9 +2,9 @@ import clsx from 'clsx' import { PencilIcon } from '@heroicons/react/outline' import { User } from 'common/user' -import { useEffect, useState } from 'react' +import { useState } from 'react' import { useFollowers, useFollows } from 'web/hooks/use-follows' -import { prefetchUsers, useUser } from 'web/hooks/use-user' +import { usePrefetchUsers, useUser } from 'web/hooks/use-user' import { FollowList } from './follow-list' import { Col } from './layout/col' import { Modal } from './layout/modal' @@ -105,16 +105,9 @@ function FollowsDialog(props: { const { user, followingIds, followerIds, defaultTab, isOpen, setIsOpen } = props - useEffect(() => { - prefetchUsers([...followingIds, ...followerIds]) - }, [followingIds, followerIds]) - const currentUser = useUser() - const discoverUserIds = useDiscoverUsers(user?.id) - useEffect(() => { - prefetchUsers(discoverUserIds) - }, [discoverUserIds]) + usePrefetchUsers([...followingIds, ...followerIds, ...discoverUserIds]) return ( diff --git a/web/components/referrals-button.tsx b/web/components/referrals-button.tsx index 3cf77cfd..4b4f7095 100644 --- a/web/components/referrals-button.tsx +++ b/web/components/referrals-button.tsx @@ -1,7 +1,7 @@ import clsx from 'clsx' import { User } from 'common/user' import { useEffect, useState } from 'react' -import { prefetchUsers, useUserById } from 'web/hooks/use-user' +import { usePrefetchUsers, useUserById } from 'web/hooks/use-user' import { Col } from './layout/col' import { Modal } from './layout/modal' import { Tabs } from './layout/tabs' @@ -56,9 +56,7 @@ function ReferralsDialog(props: { } }, [isOpen, referredByUser, user.referredByUserId]) - useEffect(() => { - prefetchUsers(referralIds) - }, [referralIds]) + usePrefetchUsers(referralIds) return ( diff --git a/web/hooks/use-contracts.ts b/web/hooks/use-contracts.ts index 83be4636..4d7d2f79 100644 --- a/web/hooks/use-contracts.ts +++ b/web/hooks/use-contracts.ts @@ -9,9 +9,10 @@ import { listenForHotContracts, listenForInactiveContracts, listenForNewContracts, + getUserBetContracts, getUserBetContractsQuery, } from 'web/lib/firebase/contracts' -import { QueryClient } from 'react-query' +import { useQueryClient } from 'react-query' export const useContracts = () => { const [contracts, setContracts] = useState() @@ -93,12 +94,12 @@ export const useUpdatedContracts = (contracts: Contract[] | undefined) => { : undefined } -const queryClient = new QueryClient() - -export const prefetchUserBetContracts = (userId: string) => - queryClient.prefetchQuery(['contracts', 'bets', userId], () => - getUserBetContractsQuery(userId) +export const usePrefetchUserBetContracts = (userId: string) => { + const queryClient = useQueryClient() + return queryClient.prefetchQuery(['contracts', 'bets', userId], () => + getUserBetContracts(userId) ) +} export const useUserBetContracts = (userId: string) => { const result = useFirestoreQueryData( diff --git a/web/hooks/use-portfolio-history.ts b/web/hooks/use-portfolio-history.ts index 5abfdf11..1945eb7a 100644 --- a/web/hooks/use-portfolio-history.ts +++ b/web/hooks/use-portfolio-history.ts @@ -1,19 +1,22 @@ -import { QueryClient } from 'react-query' +import { useQueryClient } from 'react-query' import { useFirestoreQueryData } from '@react-query-firebase/firestore' import { DAY_MS, HOUR_MS } from 'common/util/time' -import { getPortfolioHistoryQuery, Period } from 'web/lib/firebase/users' - -const queryClient = new QueryClient() +import { + getPortfolioHistory, + getPortfolioHistoryQuery, + Period, +} from 'web/lib/firebase/users' const getCutoff = (period: Period) => { const nowRounded = Math.round(Date.now() / HOUR_MS) * HOUR_MS return periodToCutoff(nowRounded, period).valueOf() } -export const prefetchPortfolioHistory = (userId: string, period: Period) => { +export const usePrefetchPortfolioHistory = (userId: string, period: Period) => { + const queryClient = useQueryClient() const cutoff = getCutoff(period) return queryClient.prefetchQuery(['portfolio-history', userId, cutoff], () => - getPortfolioHistoryQuery(userId, cutoff) + getPortfolioHistory(userId, cutoff) ) } diff --git a/web/hooks/use-prefetch.ts b/web/hooks/use-prefetch.ts index 3724d456..46d78b3c 100644 --- a/web/hooks/use-prefetch.ts +++ b/web/hooks/use-prefetch.ts @@ -1,11 +1,12 @@ -import { prefetchUserBetContracts } from './use-contracts' -import { prefetchPortfolioHistory } from './use-portfolio-history' -import { prefetchUserBets } from './use-user-bets' +import { usePrefetchUserBetContracts } from './use-contracts' +import { usePrefetchPortfolioHistory } from './use-portfolio-history' +import { usePrefetchUserBets } from './use-user-bets' export function usePrefetch(userId: string | undefined) { const maybeUserId = userId ?? '' - - prefetchUserBets(maybeUserId) - prefetchUserBetContracts(maybeUserId) - prefetchPortfolioHistory(maybeUserId, 'weekly') + return Promise.all([ + usePrefetchUserBets(maybeUserId), + usePrefetchUserBetContracts(maybeUserId), + usePrefetchPortfolioHistory(maybeUserId, 'weekly'), + ]) } diff --git a/web/hooks/use-user-bets.ts b/web/hooks/use-user-bets.ts index a989636f..8f0bd9f7 100644 --- a/web/hooks/use-user-bets.ts +++ b/web/hooks/use-user-bets.ts @@ -1,16 +1,17 @@ -import { QueryClient } from 'react-query' +import { useQueryClient } from 'react-query' import { useFirestoreQueryData } from '@react-query-firebase/firestore' import { useEffect, useState } from 'react' import { Bet, + getUserBets, getUserBetsQuery, listenForUserContractBets, } from 'web/lib/firebase/bets' -const queryClient = new QueryClient() - -export const prefetchUserBets = (userId: string) => - queryClient.prefetchQuery(['bets', userId], () => getUserBetsQuery(userId)) +export const usePrefetchUserBets = (userId: string) => { + const queryClient = useQueryClient() + return queryClient.prefetchQuery(['bets', userId], () => getUserBets(userId)) +} export const useUserBets = (userId: string) => { const result = useFirestoreQueryData( diff --git a/web/hooks/use-user.ts b/web/hooks/use-user.ts index b0cb1bc3..b355d87d 100644 --- a/web/hooks/use-user.ts +++ b/web/hooks/use-user.ts @@ -1,6 +1,6 @@ import { useContext } from 'react' import { useFirestoreDocumentData } from '@react-query-firebase/firestore' -import { QueryClient } from 'react-query' +import { useQueryClient } from 'react-query' import { doc, DocumentData } from 'firebase/firestore' import { getUser, User, users } from 'web/lib/firebase/users' @@ -28,12 +28,13 @@ export const useUserById = (userId = '_') => { return result.isLoading ? undefined : result.data } -const queryClient = new QueryClient() - -export const prefetchUser = (userId: string) => { - queryClient.prefetchQuery(['users', userId], () => getUser(userId)) +export const usePrefetchUser = (userId: string) => { + return usePrefetchUsers([userId])[0] } -export const prefetchUsers = (userIds: string[]) => { - userIds.forEach(prefetchUser) +export const usePrefetchUsers = (userIds: string[]) => { + const queryClient = useQueryClient() + return userIds.map((userId) => + queryClient.prefetchQuery(['users', userId], () => getUser(userId)) + ) } diff --git a/web/lib/firebase/bets.ts b/web/lib/firebase/bets.ts index 7f44786a..2da95f9d 100644 --- a/web/lib/firebase/bets.ts +++ b/web/lib/firebase/bets.ts @@ -70,20 +70,16 @@ export function listenForBets( ) } -export async function getUserBets( - userId: string, - options: { includeRedemptions: boolean } -) { - const { includeRedemptions } = options - return getValues( - query(collectionGroup(db, 'bets'), where('userId', '==', userId)) - ) - .then((bets) => - bets.filter( - (bet) => (includeRedemptions || !bet.isRedemption) && !bet.isAnte - ) - ) - .catch((reason) => reason) +export async function getUserBets(userId: string) { + return getValues(getUserBetsQuery(userId)) +} + +export function getUserBetsQuery(userId: string) { + return query( + collectionGroup(db, 'bets'), + where('userId', '==', userId), + orderBy('createdTime', 'desc') + ) as Query } export async function getBets(options: { @@ -124,22 +120,16 @@ export async function getBets(options: { } export async function getContractsOfUserBets(userId: string) { - const bets: Bet[] = await getUserBets(userId, { includeRedemptions: false }) - const contractIds = uniq(bets.map((bet) => bet.contractId)) + const bets = await getUserBets(userId) + const contractIds = uniq( + bets.filter((b) => !b.isAnte).map((bet) => bet.contractId) + ) const contracts = await Promise.all( contractIds.map((contractId) => getContractFromId(contractId)) ) return filterDefined(contracts) } -export function getUserBetsQuery(userId: string) { - return query( - collectionGroup(db, 'bets'), - where('userId', '==', userId), - orderBy('createdTime', 'desc') - ) as Query -} - export function listenForUserContractBets( userId: string, contractId: string, diff --git a/web/lib/firebase/contracts.ts b/web/lib/firebase/contracts.ts index 0fea53a0..c7e32f71 100644 --- a/web/lib/firebase/contracts.ts +++ b/web/lib/firebase/contracts.ts @@ -157,6 +157,10 @@ export function listenForUserContracts( return listenForValues(q, setContracts) } +export function getUserBetContracts(userId: string) { + return getValues(getUserBetContractsQuery(userId)) +} + export function getUserBetContractsQuery(userId: string) { return query( contracts, diff --git a/web/lib/firebase/users.ts b/web/lib/firebase/users.ts index fc024e04..4e29fb1c 100644 --- a/web/lib/firebase/users.ts +++ b/web/lib/firebase/users.ts @@ -254,6 +254,10 @@ export async function unfollow(userId: string, unfollowedUserId: string) { await deleteDoc(followDoc) } +export function getPortfolioHistory(userId: string, since: number) { + return getValues(getPortfolioHistoryQuery(userId, since)) +} + export function getPortfolioHistoryQuery(userId: string, since: number) { return query( collectionGroup(db, 'portfolioHistory'), diff --git a/web/pages/api/v0/user/[username]/bets/index.ts b/web/pages/api/v0/user/[username]/bets/index.ts index 464af52c..57648f4d 100644 --- a/web/pages/api/v0/user/[username]/bets/index.ts +++ b/web/pages/api/v0/user/[username]/bets/index.ts @@ -18,8 +18,9 @@ export default async function handler( return } - const bets = await getUserBets(user.id, { includeRedemptions: false }) + const bets = await getUserBets(user.id) + const visibleBets = bets.filter((b) => !b.isRedemption && !b.isAnte) res.setHeader('Cache-Control', 'max-age=0') - return res.status(200).json(bets) + return res.status(200).json(visibleBets) }