Suspense 도입 관련 질문입니다.
818
投稿した質問数 74
// layout.tsx
import type { Metadata } from 'next';
import { getServerSession } from 'next-auth';
import { Nunito } from 'next/font/google';
import { authOptions } from './api/auth/[...nextauth]/route';
import ClientOnly from './components/ClientOnly';
import LoginModal from './components/modals/LoginModal';
import RegisterModal from './components/modals/RegisterModal';
import Navbar from './components/navbar/Navbar';
import RQProvider from './components/providers/RQProvider';
import ToasterProvider from './components/providers/ToasterProvider';
import './globals.css';
const font = Nunito({ subsets: ['latin'] });
export const metadata: Metadata = {
title: 'SMUING',
description: 'SMUING에 오신것을 환영합니다.'
};
export default async function RootLayout({ children }: { children: React.ReactNode }) {
const session = await getServerSession(authOptions);
return (
<html lang="ko">
<body className={`${font.className} dark:bg-medium dark:text-slate-100`}>
<ClientOnly>
<RQProvider>
<ToasterProvider />
<RegisterModal />
<LoginModal />
<Navbar />
<div className="pb-20 pt-28">{children}</div>
</RQProvider>
</ClientOnly>
</body>
</html>
);
}
// page.tsx
import { HydrationBoundary, QueryClient, dehydrate } from '@tanstack/react-query';
import Container from './components/Container';
import ListingContainer from './components/listings/ListingContainer';
import { getFilteredPosts } from './lib/getFilteredPosts';
type HomeProps = {
searchParams?: {
category?: string;
};
};
const Home: React.FC<HomeProps> = async ({ searchParams }) => {
const queryClient = new QueryClient();
const category = searchParams?.category || '';
// 서버에서 불러온 데이터를 클라이언트의 리액트 쿼리가 물려받음.(하이드레이트)
await queryClient.prefetchInfiniteQuery({
queryKey: ['posts', category],
queryFn: ({ pageParam = 1 }) => getFilteredPosts(category, { pageParam }), // searchParams 전달
// 커서 값
initialPageParam: 0
});
// hydrate라는 것은 서버에서 온 데이터를 클라이언트에서 그대로, 물려받는 것 이다.
const dehydratedState = dehydrate(queryClient);
return (
<HydrationBoundary state={dehydratedState}>
<Container>
<ListingContainer />
</Container>
</HydrationBoundary>
);
};
export default Home;
안녕하세요, 제로초님 강의를 수강하면서 현재 제가 진행하고있는 프로젝트에 Suspense를 도입해보면 좋을 것 같아 진행중입니다.layout.tsx에서 정의한 Header 컴포넌트만 먼저 보여주고, page.tsx에서 보여지는 가운데에 있는 ListingContainer 부분을 Skeleton UI 형식으로 보여주고 싶은게 제가 하고싶은 행동인데, 이 경우에는 Suspense를 어떻게 적용시켜야할지 감이 안와서 질문드립니다. ListingContainer를 ListingContainerSuspense 컴포넌트로 분리하여, searchParams와, 쿼리부분 코드를 옮겨도 제대로 동작하지 않아, 다른 좋은 접근 방식이 있을지 의견을 구하고자 질문을 남기게 되었습니다. 좋은강의 항상 감사합니다!
回答 2
0
안녕하세요 강사님 강사님의 답변을 읽어보던 중에 궁금한 것이 생겨서 여기에 따로 질문드립니다
어차피 suspense 쓰실거면 prefetchInfiniteQuery도 필요없습니다. useSuspenseInfiniteQuery만 쓰시면 됩니다.
라고 말씀해주셨는데 왜 서스펜스를 사용하면 prefetch가 필요없어지는지 알 수 있을까요?
0
그렇다면 혹시 강의에서 진행해주신 실습 내용이었던
// (afterLogin)\home\page.tsx
import { HydrationBoundary, QueryClient, dehydrate } from '@tanstack/react-query';
import Post from '../_component/Post';
import PostForm from './_component/PostForm';
import Tab from './_component/Tab';
import TabProvider from './_component/TabProvider';
import styles from './home.module.css';
import { revalidatePath, revalidateTag } from 'next/cache';
import { getPostRecommends } from './_lib/getPostRecommends';
import PostRecommends from './_component/PostRecommends';
import TabDecider from './_component/TabDecider';
import { Suspense } from 'react';
import TabDeciderSuspense from './_component/TabDeciderSuspense';
import Loading from './loading';
const Home = async () => {
return (
<main className={styles.main}>
<TabProvider>
{/* 로딩이 필요 없는 애들은 Suspense 바깥으로 */}
<Tab />
<PostForm />
<Suspense fallback={<Loading />}>
<TabDeciderSuspense />
</Suspense>
</TabProvider>
</main>
);
};
export default Home;
import { Suspense } from 'react';
import TabDecider from './TabDecider';
import { HydrationBoundary, QueryClient, dehydrate } from '@tanstack/react-query';
import { getPostRecommends } from '../_lib/getPostRecommends';
export default async function TabDeciderSuspense() {
const queryClient = new QueryClient();
// 추천 게시글 정보
await queryClient.prefetchInfiniteQuery({
queryKey: ['posts', 'recommends'],
queryFn: getPostRecommends,
initialPageParam: 0, //cursor값
});
const dehydreatedState = dehydrate(queryClient);
return (
<HydrationBoundary state={dehydreatedState}>
<TabDecider /> {/* <PostRecommends /> or <FollowingPosts /> */}
</HydrationBoundary>
);
}
이 부분에서는 suspense와 prefetchInfiniteQuery를 같이 사용하셨는데 이 부분은 강사님이 답글로 말씀 해주신 부분과 다른 맥락인가요?
1
여기서의 suspense 대상은 followingPosts였습니다. useSuspenseQuery로 바꾼 대상이요.
postRecommends는 suspense로 안 바꿨습니다.
0
아ㅠㅠ 조금 헷갈렸던 것이 강사님의
Suspense로 Streaming하여 최적화하기(feat. loading.tsx, error.tsx) 강의 에서 20분30초에
(prefetch한 것을 받아서 hydrate하는) PostRecommends.tsx 에서 useInfiniteQuery 를 useSuspenseInfiniteQuery 로 변경하셨더라구요 그리고 이 부분도 Suspense로 감싼 혜택을 볼 수 있다고 말씀하셨는데
깃허브에 올라간 코드를 보면 다시 useInfiniteQuery로 사용되고 있네요
그러면 이 부분은 useInfiniteQuery 로 사용하는 것으로 이해하면 될까요?
0
줄바꿈 확인해주세요
1
searchParams 부분을 옮기는 게 아니라 props로 내려주시면 됩니다. 어차피 suspense 쓰실거면 prefetchInfiniteQuery도 필요없습니다. useSuspenseInfiniteQuery만 쓰시면 됩니다.
캡처링부분 질문있습니다.
0
74
2
깃에 소스코드를 찾을 수 없습니다.
0
113
2
useInfiniteQuery promise와 react use 사용시 페이지 무한 로딩
0
98
1
import 파일 경로를 찾지 못 해서 에러가 발생합니다.
0
109
2
css 라이브러리 추천 부탁드립니다
0
140
2
팔로우 추천 목록이 빈 배열로 들어옵니다.
0
130
1
게시물 업로드 시 userId가 undefined로 들어가는 오류
0
119
1
useSuspenseQuery 사용 시 SSR 401 이슈 관련
0
171
1
리액트 쿼리 useinfinitequery 무한스크롤 구현 시 페이지가 이동할 경우 데이터가 보존되게 할 수 있나요??
0
184
3
폴링이 필요없는 이유
0
93
2
next Request Memoization과 react cache
0
108
2
seo 최적화 기준은 데이터 fetching인가요 아님 데이터 렌더링인가요?
0
84
2
next.js 서버fetch 에러 fallback ui 구현 방법
0
173
2
프레임워크 여론 파악법
0
125
2
필터옵션이 많은 페이지에서 서버 fetch를 하는게 맞는걸까요??
0
103
2
서버 fetch suspense 로 감싸고 새로고침 시 잠시 빈 화면이 노출된 후 fallback ui가 노출됩니다.
0
102
2
template.tsx 내 서버fetch 응답값과 클라이언트 컴포넌트 상태값 싱크가 맞지 않는 이슈
0
66
2
Auth.js 사용 시 authorize 함수가 호출되지 않습니다
0
131
2
next.js 에서 로그인에 관하여
0
138
1
Next의 route handler에 대한 질문이 있습니다.
0
101
2
게시판 리스트 만들때 use client를 어디서부터 집어넣어야할지 모르겠습니다
0
97
2
프라이빗 폴더를 해야 하는 이유가 모호한 것 같아요.
0
85
2
vanilla-extract 못찾는 문제
0
229
2
fetch 캐싱과 revalidate 관련
0
84
2

