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을 구성한다.