Blog reads tells us how often our content has been read. They help us understand how much traffic our content has been getting and we can use this data to strategize and repurpose our content accordingly.
What we will be building
This post will discuss using the react-intersection-observer library to implement a blog read counter that is incremented when a user has read 70 percent of our blog post. These blog reads are stored on a database. You don’t need a custom server to manage this.
To get the most out of this project, we require the following:
A basic understanding of CSS, JavaScript, and React.jsDocker Desktop is installed on the computer, run the docker -v command to verify if we have docker desktop installed, if not, install it from here
An Appwrite instance running on our computer; check out this article to create a local Appwrite instance. We will use Appwrite’s powerful database service and experience to manage our analytics data.
Setting up our Next.js app
Next.js is an open-source React framework that enables us to build server-side rendered static web applications.
To create our Next.js app, we navigate to our preferred directory and run the terminal command below:
npx create-next-app@latest
# or
yarn create next-app
After creating our app, we change the directory to the project and start a development server with:
Appwrite is an open-source, end-to-end, back-end server solution that allows developers to build applications faster.
To use Appwrite in our Next.js application, we install the Appwrite client-side SDK for web applications.
npm install appwrite
Creating a new Appwrite project
During the creation of the Appwrite instance, we specified what hostname and port we see our console. The default value is localhost:80.
We go to localhost:80 and create a new account to see our console.
On our console, there is a Create Project ****button. Click on it to start a new project.
Our project dashboard appears once we have created the project. At the top of the page, there is a Settings bar. Click it to access the Project ID and API Endpoint.
We copy the Project ID and API Endpoint, which we need to initialize the Appwrite Web SDK.
In our project's root directory, we create a utils.js file to initialize our Web SDK.
import{Appwrite}from'appwrite';// Init your Web SDKexportconstsdk=newAppwrite();sdk.setEndpoint('http://localhost/v1')// Your API Endpoint.setProject('625d9071b3fc17c7bfb6')// Your project ID;
Creating an anonymous user session
Appwrite requires a user to sign in before reading or writing to a database to enable safety in our application. However, they allow us to create an anonymous session for small projects like this.
We use a function to create an anonymous user session once this application mounts. We will run this createAnoymousSession function later in this tutorial.
import{Appwrite}from'appwrite';// Init your Web SDKexportconstsdk=newAppwrite();sdk.setEndpoint('http://localhost/v1')// Your API Endpoint.setProject('625d9071b3fc17c7bfb6')// Your project ID;//Creating anonymous SessionexportconstcreateAnonymousSession=async()=>{try{awaitsdk.account.createAnonymousSession();}catch(err){console.log(err)}}
Creatingthecollection and attributes
In the Appwrite web Console, we click on Database on the left side of the dashboard.
We create a collection in our database tab by clicking on the Add Collection button. This action redirects us to a Permissions page.
At the Collection Level, we want to assign a Read Access and Write Access with a role:all ****value. You can modify these permissions to specify who has access to read or write to our database.
Next, we go to our Attributes tab to create the properties we want a document to have.
We create an integer attribute of blogCount.
Creating an Appwrite Document
After creating the attributes our document will have, we go to the Documents section of the Database.
Next, we click on the Add Document button and input a zero value to create a document in our collection. This value represents the blog reads.
On the right of our newly created document, we copy our Collection ID and Document ID, which we need to perform functions on this document.
Creating the Blog Post.
In our index.jsx file, we create a sample blog post that we will use to measure and store our blog reads.
Utilizing React-intersection-observer to count blog reads
The react-intersection-observer library allows us to run a function or perform a task when a part of the website is visible in the viewport. We want to increase our blog count reads when a user has read 70 percent of the blog post with this logic.
import{useEffect,useState}from'react';import{useInView}from'react-intersection-observer';constHome=()=>{const{ref:myRef,inView}=useInView();const[appBlogRead,setAppBlogRead]=useState(0)const[blogCount,setBlogCount]=useState()return (<divclassName="blog">{/* The rest of the app goes here */}
...
</div>)}exportdefaultHome;
In the code block above, we do the following:
Import the react-intersection-observeruseView hook in our index.js file
Destructure the useView hook to get a ref that we assign to the element we want to monitor and an inView status to tell us if the element is present on the screen
Create two state variables, an appBlogRead variable to hold how many times the blog has been read per mount, which will not be more than one, and a blogCount variable to store how many times our blog has been read in general, we will update this variable with the value from our database
Next, in our index.jsx file, we pass our blogCount variable to the h3 element to display our blog reads.
<h3>Blog reads: {blogCount}</h3>
Understanding that we only want a read to count when a user has gone through 70 percent of the page, we add the ref to an element in the last quarter of our blog post. Doing this ensures that a read will not count unless that element has been on screen.
<divclassName="blog"><divclassName="nav"></div><divclassName="blog-container"><divclassName="writer"><divclassName="writer-image"></div><divclassName="writer-name">Adut Elsesser</div></div><divclassName="blog-header"><h3>Blog reads: {blogCount}</h3><h2>Mind on the road, your dilated eyes</h2><p>Watch the clouds float, white Ferrari</p></div><divclassName="blog-image"></div><divclassName="blog-story-container"><p>
Had a good time
(Sweet 16, how was I supposed to know anything?I let you out at CentralI didn't care to state the plainKept my mouth closedWe're both so familiarWhite Ferrari, good times
</p><p>
Stick by me, close by me You were fine You were fine here That's just a slow body You left when I forgot to speak So I text to speech, lesser speeds Texas speed, yes Basic takes its toll on me, Eventually, eventually, yes Ah, on me eventually, eventually, yes I care for you still and I will forever That was my part of the deal, honest We got so familiar Spending each day of the year, White Ferrari Good times In this life, life In this life, life
</p>{/* The ref */}<pref={myRef}>
One too many years Some tattooed eyelids on a facelift Mind over matter is magic I do magic If you think about it it'll be over in no time And that's life I'm sure we're taller in another dimension You say we're small and not worth the mention
</p><p>
You're tired of movin', your body's achin' We could vacay, there's places to go Clearly this isn't all that there is Can't take what's been given But we're so okay here, we're doing fine Primal and naked You dream of walls that hold us imprisoned It's just a skull, least that's what they call it And we're free to roam
</p></div></div></div>
Next, we use the useEffect hook to check if the element we are monitoring is in view and if our appBlogRead variable is less than one. If these statements are true, we want to add a read count to our appBlogRead and blogCount variable.
Create a handleBlogCount function that finds a collection using the collection ID parameter, this function updates the blogCount variable using its response
Create a updateBlogCount function that finds a document using its collection ID and document ID parameters,updateBlogCount function then updates the document using the blogCount variable, these collection and document ID are from the document we created at the start of this tutorial
Use the React useEffect to fire off the createAnonymousSession in our utils.js file and the handleBlogCount function once our application mounts
Runs our updateBlogCount function each time our blogCount variable is updated using React useEffect hook
We have created a robust blog post read counter in Next.js with this.
Read about 70 percent of the blog post to see the blog post read increase on the page and in the database.
Conclusion
This article discussed tracking blog reads with the react-intersection observer library, storing and retrieving these reads using an Appwrite database. As the post creates the base for an analytics implementation, update the code to restrict the blog count to only one read per user session.