🔧 AI Nachrichten Major AI platforms go down in unprecedented simultaneous outage(03.09.2026 um 17:34 Uhr)
🔧 AI Nachrichten ChatGPT, Claude, and Grok Down? Users Report Widespread Outages(03.09.2026 um 19:14 Uhr)
🔧 AI Nachrichten OpenAI Launches GPT-6 Astra, Says We May Have Entered the AGI Era(03.09.2026 um 22:08 Uhr)
🔧 AI Nachrichten Claude Comes to CarPlay as Fifth Major AI Chatbot App(05.09.2026 um 05:31 Uhr)
🔧 AI Nachrichten OpenAI’s GPT-6 Astra Is AGI, Says NVIDIA CEO Jensen Huang(07.09.2026 um 06:31 Uhr)
🔧 AI Nachrichten Blame AI companies for Mac mini and Mac Studio shortage(31.08.2026 um 10:32 Uhr)
🔧 AI Nachrichten Major AI platforms go down in unprecedented simultaneous outage(03.09.2026 um 17:34 Uhr)
🔧 AI Nachrichten ChatGPT, Claude, and Grok Down? Users Report Widespread Outages(03.09.2026 um 19:14 Uhr)
🔧 AI Nachrichten OpenAI Launches GPT-6 Astra, Says We May Have Entered the AGI Era(03.09.2026 um 22:08 Uhr)
🔧 AI Nachrichten Claude Comes to CarPlay as Fifth Major AI Chatbot App(05.09.2026 um 05:31 Uhr)
🔧 AI Nachrichten OpenAI’s GPT-6 Astra Is AGI, Says NVIDIA CEO Jensen Huang(07.09.2026 um 06:31 Uhr)
🔧 AI Nachrichten Blame AI companies for Mac mini and Mac Studio shortage(31.08.2026 um 10:32 Uhr)

🔧 Programmierung 🕛 kürzlich 11 Min Lesezeit
0

Epic Next JS 15 Tutorial Part 8: Search and Pagination in Next.js

↗ Quelle (dev.to)
🗣️ Stimme:
📑 Inhaltsübersicht

We are making amazing progress. We are now in the final stretch. In this section, we will look at Search and Pagination.












It is a Client Component hook that lets you read the current URL's query string.


We use it in our code to get our current parameters from our url.



Then, we use the new URLSearchParams to update our search parameters. You can learn more about it : Allows us to access the router object inside any function component in your app. We will use the replace method to prevent adding a new URL entry into the history stack.


  • usePathname : Used to prevent making an api call on every keystroke when using our Search component.




  • Install the use-debounce package from



    Excellent. Now that our Search component shows up, let's move on to the second part. We'll pass our query search through our getSummaries function and update it accordingly to allow us to search our queries.



    To make the search work, we will rely on the following parameters.




    • sorting: we will sort all of our summaries in descending order, ensuring that the newest summary appears first.


    • filters: The filters we will use $or operator to combine our search conditions. This means the search will return summaries based on the fields we will filter using $containsi, which will ignore case sensitivity.




    Let's look inside our src/data/loaders.ts file and update the following code inside our getSummaries function.




    CODE
    export async function getSummaries() {
    const url = new URL("/api/summaries", baseUrl);
    return fetchData(url.href);
    }






    Here are the changes we are going to make.




    CODE
    export async function getSummaries(queryString: string) {
    const query = qs.stringify({
    sort: ["createdAt:desc"],
    filters: {
    $or: [
    { title: { $containsi: queryString } },
    { summary: { $containsi: queryString } },
    ],
    },
    });
    const url = new URL("/api/summaries", baseUrl);
    url.search = query;
    return fetchData(url.href);
    }






    We will create a query to filter our summaries on the title and summary.



    Now, we have one more step before testing our search. Let's navigate back to the src/app/dashboard/summaries folder and make the following changes inside our page.tsx file.



    We cannot pass and utilize our query params since we just updated our getSummaries function.




    CODE
    const { data } = await getSummaries(query);






    Now, let's see if our search is working.



    ;



    So, run the following command to get all the necessary dependencies.




    CODE
    npx shadcn@latest add pagination






    And add the following code to your components/custom folder file called pagination-component.tsx.




    CODE
    "use client";
    import { FC } from "react";
    import { usePathname, useSearchParams, useRouter } from "next/navigation";

    import {
    Pagination,
    PaginationContent,
    PaginationItem,
    } from "@/components/ui/pagination";

    import { Button } from "@/components/ui/button";

    interface PaginationProps {
    pageCount: number;
    }

    interface PaginationArrowProps {
    direction: "left" | "right";
    href: string;
    isDisabled: boolean;
    }

    const PaginationArrow: FC<PaginationArrowProps> = ({
    direction,
    href,
    isDisabled,
    }) => {
    const router = useRouter();
    const isLeft = direction === "left";
    const disabledClassName = isDisabled ? "opacity-50 cursor-not-allowed" : "";

    return (
    <Button
    onClick={() => router.push(href)}
    className={`bg-gray-100 text-gray-500 hover:bg-gray-200 ${disabledClassName}`}
    aria-disabled={isDisabled}
    disabled={isDisabled}
    >
    {isLeft ? "«" : "»"}
    </Button>
    );
    };

    export function PaginationComponent({ pageCount }: Readonly<PaginationProps>) {
    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()}`;
    };

    return (
    <Pagination>
    <PaginationContent>
    <PaginationItem>
    <PaginationArrow
    direction="left"
    href={createPageURL(currentPage - 1)}
    isDisabled={currentPage <= 1}
    />
    </PaginationItem>
    <PaginationItem>
    <span className="p-2 font-semibold text-gray-500">
    Page {currentPage}
    </span>
    </PaginationItem>
    <PaginationItem>
    <PaginationArrow
    direction="right"
    href={createPageURL(currentPage + 1)}
    isDisabled={currentPage >= pageCount}
    />
    </PaginationItem>
    </PaginationContent>
    </Pagination>
    );
    }






    Again, we are using our familiar hooks from before to make this work, usePathname, searchParams, and useRouter in a similar way as we did before.



    We are receiving pageCount via props to see our available pages. Inside the PaginationArrow component, we use useRouter to programmatically update our URL via the push method on click.



    Let's add this component to our project. In our components/custom folder, create a PaginationComponent.tsx file and paste it into the above code.



    Now that we have our component, let's navigate to src/app/dashboard/summaries/page.tsx and import it.




    CODE
    import { PaginationComponent } from "@/components/custom/pagination-component";






    Now update our SearchParamsProps interface to the following.




    CODE
    interface SearchParamsProps {
    searchParams?: {
    page?: string;
    query?: string;
    };
    }






    Now, let's create a currentPage variable to store the current page we get from our URL parameters.




    CODE
    const currentPage = Number(searchParams?.page) || 1;






    Now, we can pass our currentPage to our getSummaries function.




    CODE
    const { data } = await getSummaries(query, currentPage);






    Now, let's go back to our loaders. tsx file and update the getSummaries with the following code to utilize our pagination.




    CODE
    export async function getSummaries(queryString: string, currentPage: number) {
    const PAGE_SIZE = 4;

    const query = qs.stringify({
    sort: ["createdAt:desc"],
    filters: {
    $or: [
    { title: { $containsi: queryString } },
    { summary: { $containsi: queryString } },
    ],
    },
    pagination: {
    pageSize: PAGE_SIZE,
    page: currentPage,
    },
    });
    const url = new URL("/api/summaries", baseUrl);
    url.search = query;
    return fetchData(url.href);
    }






    In the above example, we use Strapi's pagination fields and pass pageSize and page fields. You can learn more about Strapi's pagination



    Excellent, it is working.






    Conclusion



    This Next.js with Strapi CMS tutorial covered how to implement search and pagination functionalities. Hope you are enjoying this tutorial.



    We are almost done. We have two more sections to go, including deploying our project to Strapi Cloud and Vercel.



    See you in the next post.






    Note about this project



    This project has been updated to use Next.js 15 and Strapi 5.



    If you have any questions, feel free to stop by at our .



    You can also find the blog post content in the Strapi Blog.



    Feel free to make PRs to fix any issues you find in the project, or let me know if you have any questions.



    Happy coding!




    • Paul

    Vollständiger Original-Bericht
    Ausführliche Details, Code-Beispiele & Hersteller-Stellungnahme auf dev.to.
    ↗ Original-Artikel auf dev.to lesen
    Wie bewertest du diesen Beitrag?
    1 Klick Feedback
    Teilen mit Netzwerk & Team:

    Community-Analysen & Experten-Meinungen 0

    Verfasse deine eigene Analyse, teile Workarounds oder diskutiere diesen Vorfall im Blog.
    Noch keine Community-Analyse verfasst. Markiere einen Textabschnitt oder klicke oben auf Eigene Analyse verfassen“!
    Community Pulse: Relevanz-Einschätzung
    1 Klick Experten-Votum
    🔴 Akute Relevanz 0%
    🟡 In Evaluierung 0%
    🟢 Keine Auswirkung 0%
    Spannende Innovation 0%
    Verwandte Story-Cluster & Quellen (Vektor-KI)
    Port 8095 Engine
    3 Quellen
    GPT-6 Astra Release Today? OpenAI’s Next Major AI Model Is Almost Here
    1 Quelle
    Apple accuses OpenAI of destroying evidence as trade-secrets fight intensifies
    1 Quelle
    Major AI platforms go down in unprecedented simultaneous outage
    Ähnliche Beiträge
    🔍 Verwandte News

    Auch interessante Nachrichten Epic Next JS 15 Tutorial Part 8: Search and Pagination in Next.js

    Thematisch verwandte Begriffe: Epic, Next, Tutorial, Part · 6 Treffer

    Laden...

    Videos werden geladen ...

    Laden...

    Beiträge werden geladen ...

    Laden...

    Videos werden geladen ...

    Laden...

    Beiträge werden geladen ...

    Laden...

    Videos werden geladen ...

    Laden...

    Beiträge werden geladen ...

    Laden...

    Videos werden geladen ...

    Laden...

    Beiträge werden geladen ...

    Laden...

    Videos werden geladen ...