supabase ❤ nextjs

Adding view count to your Nextjs Blog

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;

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 };
  • /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 });
}

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;

Our views in action:

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

You can find me at:

https://100lvlmaster.in

--

--

--

onw to 10x developer

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

Array Destructuring

Authentication — Cookie v.s. JWT

My journey from CSS Modules to CSS-in-JS

LEARN CONTEXT API THROUGH EXAMPLE

Downloading QR code from the react-qrcode-logo library

How To Pass Value From One HTML Page To Another Using JavaScript

Publishing your npm package

Components in Javascript

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Navin Kodag

Navin Kodag

onw to 10x developer

More from Medium

Handling Previews in a Headless Architecture — Strapi and Next.js

Secure your Next.JS Application with Asgardeo and Next-Auth

Complete email/password authentication with firebase-9 and nextjs.

NextJS Link vs useRouter in Navigating.