streaming
은 경로를 작은 chunk
로 분해한 후 서버에서 클라이언트로 점진적으로 데이터를 전송받는 기술을 의미한다.streaming
을 이용하면 느린 데이터 요청이 하나라도 존재할 경우 전체 페이지를 차단(block)하는 것을 방지할 수 있다.streaming
을 두 가지 방법으로 구현할 수 있다.loading.tsx
파일을 생성한다.<Suspense>
를 적용한다.// loading.tsx
export default function Loading() {
return <div>Loading...</div>;
}
loading.tsx
파일은 해당 페이지의 데이터가 로드되는 동안 로딩 UI를 대신 보여주도록 한다.<Sidebar>
는 정적 UI이기 때문에 즉시 보여진다. 사용자는 데이터가 로드되는 동안 <Sidebar>
에서 상호작용 할 수 있다.loading.tsx
에 적용된 모든 UI는 정적 파일로, 사용자에게 로딩 중에 먼저 보여지며 그동안 나머지 동적 컨텐츠가 서버에서 클라이언트로 스트리밍된다.(overview)
폴더를 생성하면 loading.tsx
파일은 /dashboard
페이지에만 적용되며 /dashboard/invoices
페이지나 /dashboard/customers
페이지에 영향을 미치지 않는다.()
를 사용해서 새로운 폴더를 생성하면(라우트 그룹을 사용하면), 이는 URL 경로에 포함되지 않는다. 따라서 /dashboard/(overview)/page.tsx
가 아닌 /dashboard
경로가 생성될 것이다.<Suspense fallback={<RevenueChartSkeleton />}>
<RevenueChart />
</Suspense>
Suspense
로 컴포넌트를 감싸면 데이터가 로드되는 동안 전체 페이지를 차단하지 않으며, 해당 컴포넌트 부분에만 fallback UI를 대신 보여준다.streaming
을 적용하는 것보다는 데이터 fetching을 컴포넌트 레벨로 내려서 Suspense
를 적용하는 것을 추천한다.검색어 입력값을 관리하기 위해 클라이언트의 state
가 아닌 URL search params
를 사용하는 데는 몇 가지 장점이 있다.
URL parameters
를 서버에서 직접 사용하여 초기 상태를 렌더링할 수 있으므로 서버 렌더링을 보다 쉽게 처리할 수 있다.검색 기능을 구현하기 위해 Next.js의 세 가지 클라이언트 hooks를 사용한다.
useSearchParams
: 현재 URL의 parameter
에 접근할 수 있다. 예를 들어 /dashboard/invoices?page=1&query=pending
라는 URL의 search params
는 다음과 같다. {page: '1', query: 'pending'}
usePathname
: 현재 URL의 pathname을 읽어온다, 예를 들면 /dashboard/invoices
페이지의 pathname은 /dashboard/invoices
가 될 것이다.useRouter
: 다양한 메서드를 사용해서 클라이언트 컴포넌트 간에 페이지를 이동할 수 있다.검색 구현 단계
1. 사용자가 input에 입력한 값을 받는다.
2. URL에 search params
를 업데이트한다.
3. input 입력값과 URL의 동기화를 유지한다.
4. 입력값을 반영하여 테이블의 데이터를 업데이트한다.
import { useSearchParams, usePathname, useRouter } from 'next/navigation';
const searchParams = useSearchParams();
const pathname = usePathname();
const { replace } = useRouter();
const handleSearch = useDebouncedCallback((term) => {
const params = new URLSearchParams(searchParams);
params.set('page', '1');
if (term) {
params.set('query', term);
} else {
params.delete('query');
}
replace(`${pathname}?${params.toString()}`);
}, 300);
new URLSearchParams
로 인스턴스를 생성한다.?query='검색어'
와 같이 query string
을 업데이트한다.replace()
를 이용해 query string
이 반영된 URL로 업데이트한다. 이때 Next.js의 client-side navigation
덕분에 페이지는 다시 로드되지 않는다.debounce
를 적용해 검색 기능을 최적화했다.<input
onChange={(e) => {
handleSearch(e.target.value);
}}
defaultValue={searchParams.get('query')?.toString()}
/>
defatulValue
에 searchParams
의 값을 전달한다.export default async function InvoicesTable({
query,
currentPage,
}: {
query: string;
currentPage: number;
}) {
const invoices = await fetchFilteredInvoices(query, currentPage);
// ...
}
import { usePathname, useSearchParams } from 'next/navigation';
const pathname = usePathname();
const searchParams = useSearchParams();
const currentPage = Number(searchParams.get('page')) || 1;
const createPageURL = (pageNumber: number | string) => {
const params = new URLSearchParams(searchParams);
params.set('page', pageNumber.toString());
return `${pathname}?${params.toString()}`;
};
createPageURL
이 현재 search parameters
의 인스턴스를 생성한다.page
파라미터를 업데이트한다.pathname
과 업데이트된 search parameters
를 이용해서 URL을 구성한다.