TIL

2024.04.05 TIL #Tanstack_Query #prefetch #dehydration

inz1234 2024. 5. 3. 03:04

๐Ÿ“Œ Task TODOLIST

- [x] ๋ถˆํ•„์š”ํ•œ ์„œ๋ฒ„ ์š”์ฒญ ์ค„์ด๊ธฐ

- [x] TTV ์ค„์ด๊ธฐ


๐Ÿšจ  TroubleShotting

TTV๋ฅผ ์ค„์ด๊ณ ์ž ์ดˆ๊ธฐ์— ๊ฐ€์žฅ ์ตœ์‹  ๋ฉ”์„ธ์ง€ 10๊ฐœ๋งŒ ๊ฐ€์ ธ์˜ค๋„๋ก ํ–ˆ๋˜ ์•ผ๋ฌด์ง„ ์†Œ๋ง์€.. ๊ฑฐ๊พธ๋กœ ๋Œ์•„๊ฐ€๊ณ  ์žˆ์—ˆ๋‹ค.

๋ถˆํ•„์š”ํ•œ ์„œ๋ฒ„์š”์ฒญ๊ณผ TTV๋ฅผ ์ค„์ด์ž.

Why(์ด์œ )?

- ์ดˆ๊ธฐ์— allMsgs(์ตœ์‹  10๊ฐœ์˜ ๋ฉ”์„ธ์ง€)๋ฅผ ์„œ๋ฒ„์—์„œ ํ˜ธ์ถœ ํ›„, ๊ฐ€์žฅ ์ตœ์ƒ๋‹จ CSR ์ปดํฌ๋„ŒํŠธ InitChat.tsx์— props๋กœ ๋ฐ›์•„์„œ  setQueryData()๋กœ ์ดˆ๊ธฐ ๋ฉ”์„ธ์ง€๋ฅผ ํ˜ธ์ถœํ•จ์œผ๋กœ์จ -> ํ˜ธ๊ธฐ๋กญ๊ฒŒ TTV๋ฅผ ์ค„์ด๊ณ ์ž ํ–ˆ์œผ๋‚˜,

๋‹ค๋ฅธ ๊ณณ์—์„œ useMsgsQuery() (= useSuspenseQuery)๋ฅผ ํ˜ธ์ถœํ•˜๊ณ  ์žˆ์–ด์„œ ์•„๋ฌด๋ฆฌ ์ตœ์ƒ๋‹จ ์ปดํฌ๋„ŒํŠธ์—์„œ set์„ ํ•œ๋“ค ๋‹ค๋ฅธ ๊ณณ์—์„œ useSuspenseQuery๋กœ DB์— ์ƒˆ๋กœ์šด ๋ฉ”์„ธ์ง€๋ฅผ ์š”์ฒญํ•˜๊ธฐ ๋•Œ๋ฌธ์—, ํ™”๋ฉด์„ focus out ํ–ˆ๋‹ค๊ฐ€ ๋Œ์•„์˜ค๋ฉด setQueryData๊ฐ€ ๋ฌด์‚ฐ๋˜๊ณ  ์ „์ฒด ๋ฉ”์„ธ์ง€๊ฐ€ ๋ Œ๋”๋ง ๋˜๋Š” ์ด์Šˆ๊ฐ€ ์žˆ์—ˆ๋‹ค.

- ๋‹น์‹œ์—๋Š” ๋‚˜๋ฆ„ ํ•ด๊ฒฐํ•ด๋ณด๊ณ ์ž,
"์•„ ๊ทธ๋Ÿผ InitChat.tsx๊ฐ€ ์ตœ์ƒ๋‹จ ์ปดํฌ๋„ŒํŠธ์ด๋‹ˆ๊นŒ ์ œ์ผ ๋จผ์ € useSuspenseQuery๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด, ๋‹ค๋ฅธ ๊ณณ์—์„œ ํ˜ธ์ถœํ•˜๋Š” useSuspenseQuery๋Š” InitChat.tsx์—์„œ ํ˜ธ์ถœํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ๋‹ค ์“ฐ๊ฒ ๊ตฌ๋‚˜!" 
ํ•˜๊ณ  InitChat.tsx์—์„œ ํ˜ธ์ถœํ–ˆ์—ˆ๋‹ค.

- ๊ทธ๋Ÿฐ๋ฐ, ๊ทธ๋ ‡๊ฒŒ ๋˜๋ฉด ์„œ๋ฒ„์—์„œ๋„ ์ตœ๊ทผ 10๊ฐœ๋ฅผ ํ˜ธ์ถœํ•ด์„œ ํด๋ผ์ด์–ธํŠธ์— ๋„˜๊ธฐ๊ณ , ํด๋ผ์ด์–ธํŠธ(InitChat.tsx)์—์„œ๋„ useMsgsQuery()๋ฅผ ํ˜ธ์ถœํ•ด๋ฒ„๋ฆฌ๋Š” ๊ผด๋กœ ์„œ๋ฒ„์— ๋‘ ๋ฒˆ ํ˜ธ์ถœํ•˜๊ฒŒ ๋˜๋Š”๋ฐ ์ด๊ฒŒ ๋ฐ”๋กœ ๋ญ ํ”ผํ•˜๋ ค๋‹ค๊ฐ€ ๋˜ฅ์„ ๋ฐŸ์€...์ƒํ™ฉ์ด์—ˆ๋‹ค.  

How(๊ณผ์ •)?

(1) 1์ฐจ ์‹œํ–‰์ฐฉ์˜ค 
ok. ๊ทธ๋Ÿฌ๋ฉด ์„œ๋ฒ„์—์„œ ๋„˜๊ฒจ์ฃผ๋Š” ์ตœ์‹  10๊ฐœ ๋ฉ”์„ธ์ง€๋ฅผ ์บ์‹œ๋ฐ์ดํ„ฐ๋กœ ์“ฐ๊ณ , Inichat.tsx๋ฅผ ํฌํ•จํ•œ messages๋ฅผ ํ•„์š”๋กœ ํ•˜๋Š” ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ์—์„œ useMsgsQuery() ๋Œ€์‹  -> getQueryData()๋กœ ๋‹ค ๋ฐ”๊ฟ”๋ณด์ž.
๊ทธ๋Ÿฐ ๋‹ค์Œ, ๋ฉ”์„ธ์ง€๊ฐ€ ์ƒˆ๋กœ ์ถ”๊ฐ€๋˜๋ฉด(= payload๊ฐ€ ์ถ”๊ฐ€๋˜๋ฉด)

1) invalidateQueries๋ฅผ ํ•˜๊ณ ,
2) ๊ทธ๋Ÿผ DB์— ๋ฐ์ดํ„ฐ๊ฐ€ ์—…๋ฐ์ดํŠธ ๋  ํ…Œ๋‹ˆ
3) ๊ทธ๊ฑธ ๋‹ค์‹œ getQueryData๋ฅผ ํ•œ ๋’ค, ์œ ์ €๊ฐ€ ์ด์ „์— ๋ณด๋˜๋Œ€๋กœ ๋ Œ๋”๋ง ํ•˜๊ธฐ ์œ„ํ•ด์„œ ๊ฐ€๊ณตํ•ด์„œ setQueryData()๋ฅผ ํ•ด์•ผ๊ฒ ๋‹ค!
๋˜ ์•ผ๋ฌด์ง„ ๊ณ„ํš์„ ์งœ๋ณธ ๊ฒฐ๊ณผ,

async (payload) => {
            if (payload) {
             1) await queryClient.invalidateQueries({ queryKey: [MSGS_QUERY_KEY, chatRoomId] });
             2) const includingNew: Message[] | undefined = queryClient.getQueryData([MSGS_QUERY_KEY, chatRoomId]);
              const lastIdx =
                messages?.length && includingNew?.map((i) => i.message_id).indexOf(messages[0].message_id);
              messages &&
                includingNew &&
             3) (await queryClient.setQueryData(
                  [MSGS_QUERY_KEY, chatRoomId],
                  [...includingNew].slice(lastIdx ?? 0, includingNew.length)
                ));

invalidateQueries๋ฅผ ํ•จ์—๋„ devTools๋กœ ํ™•์ธํ•œ ์บ์‹œ๋ฐ์ดํ„ฐ๊ฐ€ ์—…๋ฐ์ดํŠธ ๋˜์ง€ ์•Š๋Š” ํ˜„์ƒ ๋ฐœ์ƒ..
=> ์ด๋กœ์จ ์•Œ๊ฒŒ๋œ ์ 
: invalidateQueries๋Š” useQuery/useSuspenseQuery๊ฐ€ ์—†์ด๋Š” ์บ์‹œ๋ฐ์ดํ„ฐ๋ฅผ ๋ฌดํšจํ™”ํ•˜๊ณ  ์ƒˆ๋กœ์šด ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„์˜ค์ง€ ๋ชป ํ•œ๋‹ค..

(2) 2์ฐจ ์‹œํ–‰์ฐฉ์˜ค
- ๊ทธ๋ ‡๋‹ด invalidateQueries๋ฅผ ์•ˆ์“ฐ๊ณ (useSuspenseQuery๋ฅผ ์–ด๋–ป๊ฒŒ๋“  ์•ˆ์“ฐ๊ฒ ๋‹ค๋Š” ์ด์ƒํ•œ ๊ณ ์ง‘...) ๊ทธ๋ƒฅ fetchํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ๋‚  ๊ฒƒ์œผ๋กœ ์จ๋ณผํ…Œ๋‹ค!

 async (payload) => {
            if (payload) {
              const includingNew = await fetchMsgs(chatRoomId) --> ๋‚ ๊ฒƒ์˜ fetch
              console.log("includingNew =>", includingNew)
              const lastIdx =
                messages?.length && includingNew?.map((i) => i.message_id).indexOf(messages[0].message_id);
              messages &&
                includingNew &&
                (await queryClient.setQueryData(
                  [MSGS_QUERY_KEY, chatRoomId],
                  [...includingNew].slice(lastIdx ?? 0, includingNew.length)
                ));
             const newArr =  messages &&
                includingNew &&
                (await queryClient.setQueryData(
                  [MSGS_QUERY_KEY, chatRoomId],
                  [...includingNew].slice(lastIdx ?? 0, includingNew.length)
                ));
                console.log("newArr =>", newArr)
            }
          }
        )

 50์„ ์ƒˆ๋กœ ์ถ”๊ฐ€ํ•˜๋ฉด ์ด๋ฒˆ์—๋Š” devTools์˜ ์บ์‹œ๋ฐ์ดํ„ฐ์™€ setQueryDataํ•œ ๋ฐ˜ํ™˜๊ฐ’์„ ์ฝ˜์†”๋กœ ์ฐ์–ด๋ณด๋‹ˆ ๋‘˜ ๋‹ค ์ž˜ ์—…๋ฐ์ดํŠธ ๋จ!
ํ•˜์ง€๋งŒ, re-๋ Œ๋”๋ง์ด ๋˜์ง€ ์•Š์Œใ…œใ…œ
์›์ธ์€ ์œ„์— useQuery๋ฅผ ์‚ฌ์šฉํ•˜๋˜ ๊ฒƒ๋“ค์„ -> ๋ชจ๋‘ getQueryData()๋กœ ๋ฐ”๊พธ์—ˆ๋‹ค๊ณ  ํ–ˆ๋Š”๋ฐ, getQueryData()๋Š” ๋ณ€๊ฒฝ๋œ ์บ์‹œ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ์ง€ ํ•˜์ง€ ๋ชปํ•˜์—ฌ re-๋ Œ๋”๋ง์„ ์ผ์œผํ‚ค์ง€ ๋ชปํ•˜๊ธฐ ๋•Œ๋ฌธ์ด์—ˆ๋‹ค..

=> ์ด ์‹œํ–‰์ฐฉ์˜ค๋“ค๋กœ ๋ฐฐ์šด ์ 
: invalidateQuries์™€ setQueryData, getQueryData ๋ชจ๋‘ useQuery/UseSuspenseQuery ์—†์ด ๋‹จ๋…์œผ๋กœ๋Š” ์บ์‹œ๋ฐ์ดํ„ฐ๋ฅผ ์•„์˜ˆ ์—…๋ฐ์ดํŠธ ํ•˜์ง€ ๋ชปํ•˜๊ฑฐ๋‚˜, ์—…๋ฐ์ดํŠธ ํ•ด๋„ re-๋ Œ๋”๋ง์„ ์ผ์œผํ‚ค์ง€ ๋ชปํ•˜์—ฌ ๋ฌด์šฉ์ง€๋ฌผ์ด ๋œ๋‹ค..  

what(๊ฒฐ๊ณผ)

๊ทธ๋Ÿฌ๋‹ค ๋ฌธ๋“.. ์˜ˆ์ „์— prefetch๋กœ dehydration ํ•ด์„œ ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ๋กœ ๋„˜๊ฒผ๋˜ ๊ฒƒ์ด ์ƒ๊ฐ๋‚ฌ๋‹ค.
๊ทธ๋ ‡์ง€๋งŒ ์‚ฌ์‹ค ์˜์‹ฌ์€ ๋๋‹ค.
'์ด๊ฒƒ๋„ ์„œ๋ฒ„์—์„œ prefetch ํ•˜์ง€๋งŒ, ์–ด์จŒ๋“  ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ์—์„œ useSuspenseQuery๋กœ ๋ถ€๋ฅด๋ฉด, ๋‘ ๋ฒˆ ํ˜ธ์ถœ๋˜๋Š” ๊ฑฐ ์•„๋‹Œ๊ฐ€?'
๊ฒฐ๊ณผ๋Š” ์•„๋‹ˆ์—ˆ๋‹ค. prefetch + dehydration ํ•ด์„œ hydration ์ „์— ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ์— ๋ฐ์ดํ„ฐ๋ฅผ ๋„˜๊ธด ๋’ค, ์ปดํฌ๋„ŒํŠธ์—์„œ useSuspense๋ฅผ ํ•ด๋„ prefetchํ•œ ๊ฒฐ๊ณผ(์ตœ์‹  10๊ฐœ ๋ฐ์ดํ„ฐ)๋ฅผ ์‚ฌ์šฉํ–ˆ๊ณ (์žฌํ˜ธ์ถœ X)
useSuspenseQuery์˜ ๋ฐ˜ํ™˜๊ฐ’์ด ์˜จ์ „ํžˆ ์ตœ์‹  10๊ฐœ์˜ ๋ฐ์ดํ„ฐ๋กœ ์ž˜ ๋ฐ˜ํ™˜๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

ํ•˜์—ฌ ๋‚˜์˜ ์ตœ์ข… ์ฝ”๋“œ๋Š”..

const ChatPage = async ({ params }: { params: { chatroom_id: string } }) => {
  const chatRoomId = params.chatroom_id;
  const supabase = serverSupabase();
  const {
    data: { user }
  } = await supabase.auth.getUser();

  const prefetchMsgs = async () => {
    const { from, to } = getFromTo(0, ITEM_INTERVAL);
    const { data: allMsgs, error } = await supabase
      .from('messages')
      .select('*')
      .eq('chatting_room_id', chatRoomId)
      .range(from, to)
      .order('created_at', { ascending: false });
    if (error || !allMsgs) {
      console.error(error.message);
    } else {
      return allMsgs;
    }
  };
  const queryClient = new QueryClient();

  await queryClient.prefetchQuery({ -----> (1)
    queryKey: [MSGS_QUERY_KEY, chatRoomId],
    queryFn: prefetchMsgs
  });

  return (
    <main>
      <HydrationBoundary state={dehydrate(queryClient)}> ----> (2)
        <Suspense fallback={<ChatLoading />}>  
          <div className="relative flex flex-row">
            <InitChat user={user} chatRoomId={chatRoomId} />
            <div className="flex lg:flex-row w-full max-sm:flex-col justify-center mx-auto">
              <section className="lg:flex lg:max-w-96 max-sm:absolute max-sm:z-50 max-sm:bg-white ">
                <SideBar chatRoomId={chatRoomId} />
              </section>
              <section className="w-full max-w-xl max-h-[calc(100vh-90px)] min-h-[36rem]  relative">
                <div className="absolute top-0 left-0">
                  <SideBarButton />
                </div>
                <div className="h-full border rounded-md flex flex-col relative ">
                  <ChatHeader chatRoomId={chatRoomId} />
                  <Suspense>
                    <ChatList user={user} chatRoomId={chatRoomId} />
                    <ChatInput />
                  </Suspense>
                </div>
              </section>
            </div>
          </div>
        </Suspense>
      </HydrationBoundary>
    </main>
  );
};

 

chatPage > InitChat.tsx
const InitChat = ({ user, chatRoomId }: { user: User | null; chatRoomId: string }) => {
  const allMsgs = useMsgsQuery(chatRoomId);