🔍 Search Page
This guide explains how to implement a full search flow using the Zezo OTT API and UI Kit, powered by React Query and Next.js App Router.
📁 Folder Structure
app/
│
├── search/
│ └── page.tsx # Server Component to fetch search results
│
├── _components/
│ └── SearchClient.tsx # Client Component for <ZezoSearch />
📄 File: app/search/page.tsx
This is a Server Component that:
- Extracts the search query from the
searchParams
object. - Calls the Zezo API Client to fetch search results.
- Passes both
initialQuery
andinitialData
to the<SearchClient />
Client Component.
✅ Usage Purpose
This file ensures that search data is fetched server-side before rendering the page. This improves SEO and performance for the search experience.
💡 Implementation
import { zezoClient } from "@/lib/zezoClient";
import SearchClient from "../_components/SearchClient";
import { IContentData } from "@zezosoft/zezo-ott-api-client";
export default async function SearchPage({
searchParams,
}: {
searchParams: { q?: string };
}) {
const query = searchParams.q?.trim() || "";
let data: IContentData[] = [];
if (query.length > 0) {
try {
const results = await zezoClient().contents.fetchSearchResults(query);
data = results.data.data || [];
} catch {
data = [];
}
}
return <SearchClient initialQuery={query} initialData={data} />;
}
📄 app/_components/SearchClient.tsx
This is a Client Component responsible for:
- Managing client-side search input
- Navigating on input change
- Displaying results using
<ZezoSearch />
from the UI Kit
🔌 Props
Prop | Type | Required | Description |
---|---|---|---|
initialQuery | string | ✅ Yes | The query string fetched from the URL |
initialData | IContentData[] | ✅ Yes | The data fetched from the server for hydration |
🧠 Logic
useState
tracks the search input.useTransition
enables low-priority routing.router.push
updates the query parameter on typing.- Results are shown only if the query is not empty.
🚀 Code Example
"use client";
import React, { useEffect, useState, useTransition } from "react";
import { useRouter } from "next/navigation";
import { Search as ZezoSearch } from "@zezosoft/zezo-ott-react-ui-kit";
import { IContentData } from "@zezosoft/zezo-ott-api-client";
interface Props {
initialData: IContentData[];
initialQuery: string;
}
export default function SearchClient({ initialQuery, initialData }: Props) {
const router = useRouter();
const [inputValue, setInputValue] = useState(initialQuery);
const [isPending, startTransition] = useTransition();
useEffect(() => {
setInputValue(initialQuery);
}, [initialQuery]);
return (
<ZezoSearch
value={inputValue}
onChange={(value) => {
setInputValue(value);
startTransition(() => {
router.push(`/search?q=${encodeURIComponent(value)}`, {
scroll: false,
});
});
}}
isLoading={isPending}
results={inputValue.trim().length > 0 ? initialData : []}
/>
);
}
📦 Props for SearchClient
Prop | Type | Description |
---|---|---|
initialQuery | string | The search term from the URL query string |
initialData | IContentData[] | The search result data from server-side prefetching |
🧠 How It Works
- URL query (
q
) is extracted on the server. - Search data is prefetched using
zezoClient()
. - Data is passed to the client via props.
<SearchClient />
renders the<ZezoSearch />
component.- Client-side navigation triggers updates on input change.
✅ This setup combines server-side data fetching with client-side hydration for optimal performance and user experience.
🖼️ UI Preview
Here’s how the Search component looks in action:
📝 Notes
- Search results must follow the
IContentData[]
format. - Ensure
QueryClientProvider
is configured at the app root (e.g.,app/layout.tsx
). <ZezoSearch />
is fully customizable — including theme, layout, empty state, and more.- No new search is triggered when the query string is empty (empty
q
param). - This implementation does not require
react-hot-toast
, keeping dependencies minimal.
💡 Tip: You can extend this setup with:
- Filter chips (genre, language, etc.)
- Pagination or infinite scroll
- Category toggles or tabs for richer discovery
Last updated on