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

How to build a Grid system in JavaScript

Django model DateTimeField

Solved — Rxjs TypeError: Cannot destructure property ‘__extends’ of tslib.js

Mocking passport githubStrategy for functional testing

React Lifecycle Methods

When to Use Node.js for Back-End — Guide for Business Owners

Submask Enumeration

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

Relational Data in Firebase Firestore

Migrating Keeps.com to Next.js

Dark Mode&Light Mode: Next.js with next-themes and Sass

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