How to actually do SEO-friendly pagination the right way

Viewed 16

I want to build pagination the proper way that is SEO-friendly and liked by google. From doing my research, it seems that there is a lot of incorrect content out there that, while it works, is poor for SEO. I assume that, because of my SEO-friendly requirement, I cannot use any state to manage the next/prev page links and so on, and I want the page to use URL params to determine the page number (e.g. /something?page=2). It sounds like /something/page/2 might also be acceptable, but I prefer URL params, especially as Facebook seems to use it so it must be a good way of doing so.

The problem is that my solution seems to have to use <a/> tags, which obviously just inefficiently reload the entire page when clicked on. When I try to replace the a tags with Link tags, the pagination stops working, and the component does not re-render when clicking on the prev/next links (but strangely, according to the react dev tools, re-renders all of the other components not in this demo, so something key must be wrong).

Here is my paginator component:

interface PaginatorProps {
    currentPage: number;
    itemCount: number;
    itemsPerPage?: number;
    path: string;
}

export const Paginator: FC<PaginatorProps> = ({
    currentPage,
    itemCount,
    itemsPerPage,
    path,
}) => {
    const totalPages: number = Math.ceil(itemCount / itemsPerPage);
    const disablePrev: boolean = currentPage <= 1;
    const disableNext: boolean = currentPage >= totalPages; // is last page (or 'above')

    if (totalPages <= 1 || !totalPages || !itemsPerPage || currentPage > totalPages) {
         return null;
    }

    let next: string = path,
        prev: string = path;

    if (currentPage + 1 <= itemCount) {
        next = `${path}?page=${currentPage + 1}`;
    }

    if (currentPage - 1 >= 1) {
        prev = `${path}?page=${currentPage - 1}`;
    }

    return (
        <div>
            <Link to={prev} className={`${disablePrev ? 'disabled' : ''}`}>
                Prev
            </Link>

            <span className={'paginationStyles.currentPage'}>
                Page {currentPage} of {totalPages}
            </span>

            <Link to={next} className={`${disableNext ? 'disabled' : ''}`}>
                Next
            </Link>
        </div>
    );
};

And an example component that uses it:

export const DataList = () => {
    const itemsPerPage: number = 3;
    const urlParams: URLSearchParams = new URLSearchParams(window.location.search);
    const currentPage: number = Number(urlParams.get('page')) || 1;
    const skip: number = (currentPage - 1) * itemsPerPage;
    const { dataCount, data, loading, error } = useGetDataList({ limit: itemsPerPage, skip });

    if (loading) return <Loading />;
    if (error) return <Error msg={error} />;
    if (!data?.length) return <p>No data found...</p>;

    return (
        <>
            <ul>
                {data.map(({ email }) => (
                    <li key={email}>{email}</li>
                ))}
            </ul>
            <Paginator
                currentPage={currentPage}
                itemCount={dataCount}
                itemsPerPage={itemsPerPage}
                path='/user/profile/affiliate/data-list'
            />
        </>
    );
};

Does anyone know how to make it re-render the component and paginate properly? Or is this the wrong approach per se?

0 Answers
Related