Skip to content

Commit 7cf83f6

Browse files
committed
Cache vote creators
1 parent 4c4f2e7 commit 7cf83f6

File tree

3 files changed

+60
-62
lines changed

3 files changed

+60
-62
lines changed

web/components/votes/vote-item.tsx

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,9 @@ import {Row as rowFor} from 'common/supabase/utils'
44
import {Content} from 'web/components/widgets/editor'
55
import {JSONContent} from '@tiptap/core'
66
import {VoteButtons} from 'web/components/votes/vote-buttons'
7-
import {getVoteCreator} from "web/lib/supabase/votes";
8-
import {useEffect, useState} from "react";
97
import Link from "next/link";
108
import {STATUS_CHOICES} from "common/votes/constants";
9+
import {useUserInStore} from "web/hooks/use-user-supabase";
1110

1211
export type Vote = rowFor<'votes'> & {
1312
votes_for: number
@@ -17,15 +16,22 @@ export type Vote = rowFor<'votes'> & {
1716
status?: string
1817
}
1918

19+
function Username(props: {
20+
creatorId: string
21+
}) {
22+
const {creatorId} = props
23+
const creator = useUserInStore(creatorId)
24+
return <>
25+
{creator?.username &&
26+
<Link href={`/${creator.username}`} className="custom-link">{creator.username}</Link>}
27+
</>;
28+
}
29+
2030
export function VoteItem(props: {
2131
vote: Vote
2232
onVoted?: () => void | Promise<void>
2333
}) {
2434
const {vote, onVoted} = props
25-
const [creator, setCreator] = useState<any>(null)
26-
useEffect(() => {
27-
getVoteCreator(vote.creator_id).then(setCreator)
28-
}, [vote.creator_id])
2935
// console.debug('creator', creator, vote)
3036
return (
3137
<Col className={'mb-4 rounded-lg border border-canvas-200 p-4'}>
@@ -37,8 +43,7 @@ export function VoteItem(props: {
3743
</Col>
3844
<Row className={'gap-2 mt-2 items-center justify-between w-full custom-link flex-wrap'}>
3945
{!!vote.priority ? <div>Priority: {vote.priority.toFixed(0)}%</div> : <p></p>}
40-
{!vote.is_anonymous && creator?.username &&
41-
<Link href={`/${creator.username}`} className="custom-link">{creator.username}</Link>}
46+
{!vote.is_anonymous && <Username creatorId={vote.creator_id}/>}
4247
</Row>
4348
</Col>
4449
</Row>

web/hooks/use-user-supabase.ts

Lines changed: 46 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,11 @@
1-
import { useEffect, useRef, useState } from 'react'
2-
import { useEffectCheckEquality } from './use-effect-check-equality'
3-
import { uniqBy, uniq } from 'lodash'
4-
import { usePersistentLocalState } from 'web/hooks/use-persistent-local-state'
5-
import { filterDefined } from 'common/util/array'
6-
import { usePersistentInMemoryState } from './use-persistent-in-memory-state'
7-
import {
8-
DisplayUser,
9-
getDisplayUsers,
10-
getFullUserById,
11-
} from 'web/lib/supabase/users'
12-
import { FullUser } from 'common/api/user-types'
1+
import {useEffect, useState} from 'react'
2+
import {useEffectCheckEquality} from './use-effect-check-equality'
3+
import {uniq, uniqBy} from 'lodash'
4+
import {usePersistentLocalState} from 'web/hooks/use-persistent-local-state'
5+
import {filterDefined} from 'common/util/array'
6+
import {usePersistentInMemoryState} from './use-persistent-in-memory-state'
7+
import {DisplayUser, getDisplayUsers, getFullUserById,} from 'web/lib/supabase/users'
8+
import {FullUser} from 'common/api/user-types'
139

1410
export function useUserById(userId: string | undefined) {
1511
const [user, setUser] = usePersistentInMemoryState<
@@ -25,8 +21,8 @@ export function useUserById(userId: string | undefined) {
2521
return user
2622
}
2723

28-
const cache = new Map<string, DisplayUser | null>()
29-
24+
// const cache = new Map<string, DisplayUser | null>()
25+
//
3026
// export function useDisplayUserById(userId: string | undefined) {
3127
// const [user, setUser] = usePersistentInMemoryState<
3228
// DisplayUser | null | undefined
@@ -51,45 +47,48 @@ const cache = new Map<string, DisplayUser | null>()
5147
// return user
5248
// }
5349

54-
export function useUsers(userIds: string[]) {
55-
const [users, setUsers] = useState<(DisplayUser | null)[] | undefined>(
56-
undefined
57-
)
58-
59-
const requestIdRef = useRef(0)
60-
useEffectCheckEquality(() => {
61-
const requestId = ++requestIdRef.current
62-
63-
const missing = userIds.filter((id) => !cache.has(id))
64-
65-
getDisplayUsers(missing).then((users) => {
66-
users.forEach((user) => {
67-
cache.set(user.id, user)
68-
})
69-
if (requestId !== requestIdRef.current) return
70-
setUsers(userIds.map((id) => cache.get(id) ?? null))
71-
})
72-
}, [userIds])
73-
74-
return users
75-
}
50+
// export function useUsers(userIds: string[]) {
51+
// const [users, setUsers] = useState<(DisplayUser | null)[] | undefined>(
52+
// undefined
53+
// )
54+
//
55+
// const requestIdRef = useRef(0)
56+
// useEffectCheckEquality(() => {
57+
// const requestId = ++requestIdRef.current
58+
//
59+
// const missing = userIds.filter((id) => !cache.has(id))
60+
//
61+
// getDisplayUsers(missing).then((users) => {
62+
// users.forEach((user) => {
63+
// cache.set(user.id, user)
64+
// })
65+
// if (requestId !== requestIdRef.current) return
66+
// setUsers(userIds.map((id) => cache.get(id) ?? null))
67+
// })
68+
// }, [userIds])
69+
//
70+
// return users
71+
// }
7672

7773
// TODO: decide whether in-memory or in-localstorage is better and stick to it
7874

7975
export function useUsersInStore(
80-
userIds: string[],
76+
userIds: (string | null)[],
8177
key: string,
8278
limit?: number
8379
) {
80+
const validUserIds = Array.from(new Set(userIds.filter((id): id is string => !!id)))
81+
8482
const [users, setUsers] = usePersistentLocalState<DisplayUser[] | undefined>(
8583
undefined,
86-
'use-users-in-local-storage' + key
84+
'use-users-in-local-storage-' + key
8785
)
8886

8987
// Fetch all users at least once on load.
9088
const [userIdsFetched, setUserIdsFetched] = useState<string[]>([])
9189
const fetchedSet = new Set(userIdsFetched)
92-
const userIdsNotFetched = userIds.filter((id) => !fetchedSet.has(id))
90+
91+
const userIdsNotFetched = validUserIds.filter((id) => !fetchedSet.has(id))
9392
const userIdsToFetch = limit
9493
? userIdsNotFetched.slice(0, limit)
9594
: userIdsNotFetched
@@ -104,5 +103,12 @@ export function useUsersInStore(
104103
})
105104
}, [userIdsToFetch])
106105

107-
return users?.filter((user) => userIds.includes(user?.id))
106+
return users?.filter((user) => validUserIds.includes(user?.id))
107+
}
108+
109+
export function useUserInStore(userId: string | null) {
110+
if (!userId) return null // early return avoids invalid key + hook calls are safe
111+
112+
const users = useUsersInStore(userId ? [userId] : [], userId ?? 'empty')
113+
return users?.[0] ?? null
108114
}

web/lib/supabase/votes.ts

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,13 @@
1-
import {run} from 'common/supabase/utils'
21
import {db} from 'web/lib/supabase/db'
32

43
import {OrderBy} from "common/votes/constants";
54

65
export const getVotes = async (params: { orderBy: OrderBy }) => {
7-
const { orderBy } = params
6+
const {orderBy} = params
87
const {data, error} = await db.rpc('get_votes_with_results' as any, {
98
order_by: orderBy,
109
});
1110
if (error) throw error;
1211

1312
return data
1413
}
15-
16-
export const getVoteCreator = async (creatorId: string) => {
17-
const {data} = await run(
18-
db
19-
.from('users')
20-
.select(`id, name, username`)
21-
.eq('id', creatorId)
22-
.limit(1)
23-
)
24-
25-
return data[0]
26-
}

0 commit comments

Comments
 (0)