5

Adding view count to your Nextjs Blog

 2 years ago
source link: https://dev.to/100lvlmaster/adding-view-count-to-your-nextjs-blog-55lj
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Alright lads, this will be a quick one. I want to add the views count functionality on my personal portfolio website's blog section.

Expected behavior:

  • Blogs Page : List of blogs -> Show count.
  • Blog Page : Particular Article -> Show count and Increment count.

How to achieve:

  • Use supabase to store count by slug
  • Stored procedure to increment count

Tools that I'll need:

  • supabase : open source firebase alternative
  • swr : data fetching

Setting up supabase table :

Create a table views with schema like such:

  • slug -> text -> primary key
  • created_at -> timestamp -> now()
  • count -> int2

Updating count:

  • Fetch count
  • Increment one
  • Fetch count again

Now we can reduce this to one db call using stored procedures:

create function increment (slug_text text)
returns void as
$$
update views
set count = count + 1
where slug = slug_text;
$$
language sql volatile;
Enter fullscreen modeExit fullscreen mode

In NextJs:

We'll define a route for ease:
- /api/view/{slug}
and then we'll use the POST request to register a view and GET to increment the view count.
Our handler code will look like this:
views.ts

import { createClient, PostgrestError } from "@supabase/supabase-js";
const supabase = createClient(
process.env.SUPABASE_URL,
process.env.SUPABASE_KEY
);
interface SupabaseResult {
    data?: { count: number };
    error?: PostgrestError;
}
///
const getViews = async (slug: string): Promise<number> => {
const { data: views, error }: SupabaseResult = await supabase
.from("views")
.select(`count`)
.match({ slug: slug })
.single();
if (error && error.details.includes(`0 rows`)) {
    const { data, error }: SupabaseResult = await supabase
    .from(`views`)
    .insert({ slug: slug, count: 1 }, { returning: `representation` })
    .single();
    return data.count;
    }
    if (!views) {
    return 0;
    }
    return views.count;
    };
///
    const registerView = async (slug: string): Promise<void> => {
    const { data, error } = await supabase.rpc("increment", {
    slug_text: slug,
    });
};
export { getViews, registerView };
Enter fullscreen modeExit fullscreen mode
  • /api/view/[slug].ts
// /api/view/[slug].ts
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
import { getViews, registerView } from "lib/views";
import type { NextApiRequest, NextApiResponse } from "next";
interface Data {
    message?: string;
    status?: number;
    count?: number;
}

///
export default async function handler(
req: NextApiRequest,
res: NextApiResponse<Data>
): Promise<void> {
const slug = req.query.slug.toString();
///
if (!slug) {
    return res.status(400).json({ message: `invalid slug` });
}
if (req.method == `POST`) {
    await registerView(slug);
}
const count = await getViews(slug);
return res.status(200).json({ count: count });
}
Enter fullscreen modeExit fullscreen mode

ViewCounter Component

  • view_counter.tsx
import fetcher from "lib/fetcher";
import { Views } from "lib/types";
import { useEffect } from "react";
import useSWR from "swr";

interface Props {
    slug: string;
}

const ViewCounter = ({ slug }: Props) => {
const { data } = useSWR<Views>(`/api/views/${slug}`, fetcher);
useEffect(() => {
    const registerView = () =>
    fetch(`/api/views/${slug}`, {
        method: "POST",
    });
    registerView();
}, [slug]);

return (
    <span>{`${
    (data?.count ?? 0) > 0 ? data.count.toLocaleString() :"–––"
    } views`}</span>
    );
};

export default ViewCounter;
Enter fullscreen modeExit fullscreen mode

Our views in action:

The code of this project lives at : https://github.com/100lvlmaster.in


You can find me at: https://100lvlmaster.in


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK