Skip to content

Commit ab574b2

Browse files
committed
✨ 스레드 프리페칭
- 메시지 프리페칭 로직을 마운트 이후로 변경, (서버사이드 시점에서 스레드 프리페칭이 되었는지 알 방도가 없음)
1 parent d895a75 commit ab574b2

File tree

4 files changed

+94
-54
lines changed

4 files changed

+94
-54
lines changed

src/apis/keys.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
11
export const getMessagesQueryKey = (threadId: string) => {
22
return ['messages', threadId]
33
}
4+
5+
export const getThreadsQueryKey = (channelId: string) => {
6+
return ['threads', channelId]
7+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
'use client'
2+
3+
import { useEffect } from 'react'
4+
5+
import { ChannelItem } from '@/apis/channels'
6+
import { getMessagesQueryKey, getThreadsQueryKey } from '@/apis/keys'
7+
import { getMessages } from '@/apis/messages'
8+
import { getThreads } from '@/apis/threads'
9+
import { SlackThreadLinkItem } from '@/app/archives/[channelId]/components/SlackThreadLinkItem'
10+
import { ArchivePannel } from '@/app/archives/components/ArchivePannel'
11+
import { SidebarChannelIcon } from '@/app/archives/components/Icons/SidebarChannelIcon'
12+
import { getQueryClient } from '@/utils/query'
13+
import { useSuspenseQuery } from '@tanstack/react-query'
14+
15+
interface ChannelPanelProps {
16+
channel: ChannelItem
17+
}
18+
19+
export const ChannelPanel = ({ channel }: ChannelPanelProps) => {
20+
const { data: threads } = useSuspenseQuery({
21+
queryKey: getThreadsQueryKey(channel.id),
22+
queryFn: async () => getThreads(channel.id),
23+
})
24+
25+
useEffect(() => {
26+
const prefetchMessages = async () => {
27+
const queryClient = getQueryClient()
28+
await Promise.all(
29+
threads.map((thread) =>
30+
queryClient.prefetchQuery({
31+
queryKey: getMessagesQueryKey(thread.head.ts),
32+
queryFn: () => getMessages(thread.head.ts),
33+
})
34+
)
35+
)
36+
}
37+
prefetchMessages()
38+
}, [threads])
39+
40+
return (
41+
<ArchivePannel
42+
className="absolute z-[1] w-full md:static"
43+
closeLink="/archives"
44+
description={channel.description}
45+
title={
46+
<div className="flex items-center">
47+
<SidebarChannelIcon className="mr-1 size-4" /> {channel.name}
48+
</div>
49+
}
50+
>
51+
<div className="flex h-0 grow flex-col overflow-y-auto">
52+
{threads.map(({ head, archivedAt, metadata }, index) => (
53+
<SlackThreadLinkItem
54+
archivedAt={archivedAt}
55+
head={head}
56+
isFirstItem={index === 0}
57+
key={head.ts}
58+
metadata={metadata}
59+
/>
60+
))}
61+
</div>
62+
</ArchivePannel>
63+
)
64+
}

src/app/archives/[channelId]/layout.tsx

Lines changed: 4 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,68 +1,20 @@
11
import { getChannel } from '@/apis/channels'
2-
import { getMessagesQueryKey } from '@/apis/keys'
3-
import { getMessages } from '@/apis/messages'
4-
import { getThreads } from '@/apis/threads'
5-
import { SlackThreadLinkItem } from '@/app/archives/[channelId]/components/SlackThreadLinkItem'
6-
import { ArchivePannel } from '@/app/archives/components/ArchivePannel'
7-
import { SidebarChannelIcon } from '@/app/archives/components/Icons/SidebarChannelIcon'
8-
import { compareSlackTimestampDesc } from '@/utils/date'
9-
import { withDehydratedState } from '@/utils/query'
10-
import { HydrationBoundary, QueryClient } from '@tanstack/react-query'
2+
import { ChannelPanel } from '@/app/archives/[channelId]/components/ChannelPanel'
113

124
interface ChannelLayoutProps {
135
params: Promise<{
146
channelId: string
157
}>
168
}
179

18-
const fetchChannelPageData = withDehydratedState(
19-
async ({ queryClient, channelId }: { channelId: string; queryClient: QueryClient }) => {
20-
const [channel, threads] = await Promise.all([getChannel(channelId), getThreads(channelId)])
21-
await Promise.all(
22-
threads.map((thread) =>
23-
queryClient.prefetchQuery({
24-
queryKey: getMessagesQueryKey(thread.head.ts),
25-
queryFn: () => getMessages(thread.head.ts),
26-
})
27-
)
28-
)
29-
30-
return {
31-
channel,
32-
threads: threads.toSorted((a, b) => compareSlackTimestampDesc(a.head.ts, b.head.ts)),
33-
}
34-
}
35-
)
36-
3710
const ChannelLayout = async ({ params, children }: React.PropsWithChildren<ChannelLayoutProps>) => {
3811
const { channelId } = await params
39-
const { dehydratedState, channel, threads } = await fetchChannelPageData({ channelId })
12+
const channel = await getChannel(channelId)
4013

4114
return (
4215
<div className="relative flex items-center gap-2">
43-
<ArchivePannel
44-
className="absolute z-[1] w-full md:static"
45-
closeLink="/archives"
46-
description={channel.description}
47-
title={
48-
<div className="flex items-center">
49-
<SidebarChannelIcon className="mr-1 size-4" /> {channel.name}
50-
</div>
51-
}
52-
>
53-
<div className="flex h-0 grow flex-col overflow-y-auto">
54-
{threads.map(({ head, archivedAt, metadata }, index) => (
55-
<SlackThreadLinkItem
56-
archivedAt={archivedAt}
57-
head={head}
58-
isFirstItem={index === 0}
59-
key={head.ts}
60-
metadata={metadata}
61-
/>
62-
))}
63-
</div>
64-
</ArchivePannel>
65-
<HydrationBoundary state={dehydratedState}>{children}</HydrationBoundary>
16+
<ChannelPanel channel={channel} />
17+
{children}
6618
</div>
6719
)
6820
}

src/app/archives/layout.tsx

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,30 @@
11
import { getChannels } from '@/apis/channels'
2+
import { getThreadsQueryKey } from '@/apis/keys'
3+
import { getThreads } from '@/apis/threads'
24
import { ArchivePannel } from '@/app/archives/components/ArchivePannel'
35
import { SidebarChannelItem } from '@/app/archives/components/SidebarChannelItem'
6+
import { withDehydratedState } from '@/utils/query'
7+
import { HydrationBoundary } from '@tanstack/react-query'
48

5-
const ArchivesLayout = async ({ children }: React.PropsWithChildren<unknown>) => {
9+
const fetchArchivesPageData = withDehydratedState(async ({ queryClient }) => {
610
const channels = await getChannels()
711

12+
await Promise.all(
13+
channels.map((channel) =>
14+
queryClient.prefetchQuery({
15+
queryKey: getThreadsQueryKey(channel.id),
16+
queryFn: () => getThreads(channel.id),
17+
})
18+
)
19+
)
20+
21+
return {
22+
channels,
23+
}
24+
})
25+
const ArchivesLayout = async ({ children }: React.PropsWithChildren<unknown>) => {
26+
const { channels, dehydratedState } = await fetchArchivesPageData()
27+
828
return (
929
<div className="relative grid h-full grid-cols-[1fr] grid-rows-[1fr] gap-2 overflow-hidden px-0 py-2 md:grid-cols-[320px_1fr] md:px-5">
1030
<ArchivePannel className="absolute z-[1] w-full md:static" title="채널">
@@ -14,7 +34,7 @@ const ArchivesLayout = async ({ children }: React.PropsWithChildren<unknown>) =>
1434
))}
1535
</div>
1636
</ArchivePannel>
17-
{children}
37+
<HydrationBoundary state={dehydratedState}>{children}</HydrationBoundary>
1838
</div>
1939
)
2040
}

0 commit comments

Comments
 (0)