<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Suman Sourabh</title>
    <description>The latest articles on DEV Community by Suman Sourabh (@sumansourabh48).</description>
    <link>https://dev.to/sumansourabh48</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1563989%2Ff1d22bd2-ded7-48c0-8cbd-c889ceaca866.png</url>
      <title>DEV Community: Suman Sourabh</title>
      <link>https://dev.to/sumansourabh48</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sumansourabh48"/>
    <language>en</language>
    <item>
      <title>Introducing Ready - Your Own PDF Reader &amp; Library</title>
      <dc:creator>Suman Sourabh</dc:creator>
      <pubDate>Sat, 12 Oct 2024 18:21:25 +0000</pubDate>
      <link>https://dev.to/sumansourabh48/introducing-ready-upload-pdf-read-anywhere-4jk1</link>
      <guid>https://dev.to/sumansourabh48/introducing-ready-upload-pdf-read-anywhere-4jk1</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/pinata"&gt;The Pinata Challenge &lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;Ready is a full stack application where you can upload your PDFs, read them inside the application itself, and find other PDFs uploaded by other users just like you. All you need is a web browser and an 'okayish' network!&lt;/p&gt;

&lt;p&gt;I have seen many people hesitate when they have to upload their stories online. I want to give them a platform where they can always be "Ready" to &lt;strong&gt;upload their books/stories&lt;/strong&gt;, so that &lt;strong&gt;other users can read them&lt;/strong&gt; too.&lt;/p&gt;

&lt;p&gt;On the other hand, users can use this website as a &lt;strong&gt;cloud storage&lt;/strong&gt; for their own documents. All they need to do is &lt;strong&gt;set the book as "Private"&lt;/strong&gt; and their book or doc will not be visible to other users!&lt;/p&gt;

&lt;p&gt;I have tried to make this site &lt;strong&gt;completely accessible&lt;/strong&gt; by allowing keyboard navigation while uploading PDFs and editing them. Moreover, I have added tooltips and alt text for the images wherever possible.&lt;/p&gt;

&lt;h3&gt;
  
  
  Capabilities/Features
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;User authentication with email, password &amp;amp; Google&lt;/li&gt;
&lt;li&gt;Upload PDF&lt;/li&gt;
&lt;li&gt;Set PDF as private or public&lt;/li&gt;
&lt;li&gt;Read PDF&lt;/li&gt;
&lt;li&gt;Download PDF&lt;/li&gt;
&lt;li&gt;Edit PDF details&lt;/li&gt;
&lt;li&gt;Delete PDF and details&lt;/li&gt;
&lt;li&gt;Browse the library of PDFs&lt;/li&gt;
&lt;li&gt;Wishlist any PDF&lt;/li&gt;
&lt;li&gt;See user statistics on dashboard (PDFs uploaded, wish listed)&lt;/li&gt;
&lt;li&gt;Dark mode support with system option&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Tech used
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Next.js&lt;/li&gt;
&lt;li&gt;&lt;a href="https://pinata.cloud/" rel="noopener noreferrer"&gt;Pinata&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Appwrite&lt;/li&gt;
&lt;li&gt;shadcn&lt;/li&gt;
&lt;li&gt;Tailwind CSS&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;Here's the live version: &lt;a href="https://ready-two.vercel.app/" rel="noopener noreferrer"&gt;Ready&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  My Code
&lt;/h2&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Sumansourabh14" rel="noopener noreferrer"&gt;
        Sumansourabh14
      &lt;/a&gt; / &lt;a href="https://github.com/Sumansourabh14/ready" rel="noopener noreferrer"&gt;
        ready
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Kindle Clone
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/Sumansourabh14/readyimage.png"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2FSumansourabh14%2Freadyimage.png" alt="alt text"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Ready&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;Ready is a full stack application where you can upload your PDFs, read them inside the application itself, and find other PDFs uploaded by other users just like you. All you need is a web browser and an 'okayish' network!&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Why?&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;I have seen many people hesitate when they have to upload their stories online. I want to give them a platform where they can always be "Ready" to upload their books/stories, so that other users can read them too.&lt;/p&gt;
&lt;p&gt;On the other hand, users can use this website as a cloud storage for their own documents.&lt;/p&gt;
&lt;p&gt;I have tried to make this site completely accessible by allowing keyboard navigation while uploading PDFs and editing them. Moreover, I have added tooltips and alt text for the images wherever possible.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Capabilities/Features&lt;/h2&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;User authentication with email, password &amp;amp; Google&lt;/li&gt;
&lt;li&gt;Upload PDF&lt;/li&gt;
&lt;li&gt;Read PDF&lt;/li&gt;
&lt;li&gt;Download PDF&lt;/li&gt;
&lt;li&gt;Edit PDF details&lt;/li&gt;
&lt;li&gt;Delete PDF and…&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Sumansourabh14/ready" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h3&gt;
  
  
  Screenshots
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Upload PDF page
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frbmwxcokaz73f2o5s6dr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frbmwxcokaz73f2o5s6dr.png" alt="Image description" width="800" height="411"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Edit PDF page
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fedr60lpzyryewy2iv26u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fedr60lpzyryewy2iv26u.png" alt="Image description" width="800" height="569"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Login page
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdlmmlca8kr9mt4hn4pls.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdlmmlca8kr9mt4hn4pls.png" alt="Image description" width="800" height="345"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Library page - Grid view (User not logged in)
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9pn6hxf8s3z7t4w2i3yw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9pn6hxf8s3z7t4w2i3yw.png" alt="Image description" width="800" height="435"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Library page - List view (User not logged in)
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fimp96bmz4un8to9qo2m7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fimp96bmz4un8to9qo2m7.png" alt="Image description" width="800" height="428"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Library page - List view (User is logged in) on Light theme
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F64p7mf90tc522t71ln9r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F64p7mf90tc522t71ln9r.png" alt="Image description" width="800" height="452"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Wishlist page - When there are no wish list items
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjy8arqj4n7yoqzu0ha37.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjy8arqj4n7yoqzu0ha37.png" alt="Image description" width="800" height="415"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Read PDF page
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvy4s71k8j121fopg9y00.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvy4s71k8j121fopg9y00.png" alt="Image description" width="800" height="376"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  More Details
&lt;/h2&gt;

&lt;p&gt;I used Pinata File API on a couple of occasions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Upload PDF&lt;/li&gt;
&lt;li&gt;Upload a thumbnail image&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's look at them below:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Upload PDF Document with Pinata
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const uploadDocFile = async () =&amp;gt; {
    if (!file) {
      return;
    }

    try {
      setUploading(true);
      const res = await uploadFile(file);
      const url = await res.json();
      setUrl(url);
      setUploading(false);
      if (!!url) {
        toast({
          description: "Document uploaded successfully!",
        });
      }
    } catch (e) {
      setUploading(false);
    }
  };
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above code, when the user clicks on "Upload Document" button, &lt;code&gt;uploadDocFile&lt;/code&gt; function gets called. This function is responsible for uploading the document to Pinata and get the file URL in return.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;code&gt;uploadFile&lt;/code&gt; function
&lt;/h4&gt;

&lt;p&gt;This function works behind the scenes of the &lt;code&gt;uploadDocFile&lt;/code&gt; function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { pinata } from "./config";

export const uploadFile = async (file) =&amp;gt; {
  const keyRequest = await fetch("/api/key");
  const keyData = await keyRequest.json();
  const upload = await pinata.upload.file(file).key(keyData.JWT);
  const urlRequest = await fetch("/api/sign", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ cid: upload.cid }),
  });
  return urlRequest;
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above code, 3 things are happening:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fetch the API key from Pinata&lt;/li&gt;
&lt;li&gt;Upload the file with the help of the API key&lt;/li&gt;
&lt;li&gt;Get the file URL, so that we can store it in database&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Fetch the API key from Pinata
&lt;/h4&gt;

&lt;p&gt;To upload files to Pinata, an API key is required. I used Next.js built-in API routes and created a GET request to fetch the API key from Pinata.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { pinata } from "@/utils/config";
import { NextResponse } from "next/server";

export const dynamic = "force-dynamic";

export async function GET(req, res) {
  try {
    const uuid = crypto.randomUUID();
    const keyData = await pinata.keys.create({
      keyName: uuid.toString(),
      permissions: {
        endpoints: {
          pinning: {
            pinFileToIPFS: true,
          },
        },
      },
      maxUses: 1,
    });
    return NextResponse.json(keyData, { status: 200 });
  } catch (error) {
    return NextResponse.json(
      { text: "Error creating API Key:" },
      { status: 500 }
    );
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Use the API key to upload file to Pinata
&lt;/h4&gt;

&lt;p&gt;In the &lt;code&gt;uploadFile&lt;/code&gt; function, I received the key from Pinata. Here, I used that key to upload the PDF to Pinata.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const upload = await pinata.upload.file(file).key(keyData.JWT);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Get the file URL to store in the database
&lt;/h4&gt;

&lt;p&gt;Using Next.js API routes, I created a POST request by sending the &lt;code&gt;cid&lt;/code&gt; property to the Pinata server and get the signed URL in return. This URL will be stored in the database as well as used to download the PDF document.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { pinata } from "@/utils/config";
import { NextResponse } from "next/server";

export const dynamic = "force-dynamic";

export async function POST(req, res) {
  try {
    const data = await req.json();
    const url = await pinata.gateways.createSignedURL({
      cid: data.cid,
      expires: 500000, // 138 hours
    });
    return NextResponse.json(url, { status: 200 });
  } catch (error) {
    return NextResponse.json(
      { text: "Error creating API Key:" },
      { status: 500 }
    );
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Upload Image with Pinata
&lt;/h3&gt;

&lt;p&gt;Similarly, I also used Pinata File API to upload thumbnail or cover images for the PDFs using the function below. This function uses the same underlying functions that were used to upload the PDF.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const uploadImageFile = async () =&amp;gt; {
    if (!image) {
      return;
    }

    try {
      setThumbnailUploading(true);
      const res = await uploadFile(image);
      const url = await res.json();
      setThumbnailUrl(url);
      setThumbnailUploading(false);
    } catch (e) {
      setThumbnailUploading(false);
    }
  };
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Ready is a place where you can just sign up or "Continue with Google" to upload your PDF document or read other digital books uploaded by others.&lt;/p&gt;

&lt;p&gt;Don't forget to try "Ready"! I need feedback!&lt;/p&gt;

&lt;p&gt;If there's any issue with the project, please create an issue on the GitHub repository mentioned in this post or reach out to me or directly comment here.&lt;/p&gt;

&lt;p&gt;Thank you!&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>pinatachallenge</category>
      <category>webdev</category>
      <category>api</category>
    </item>
    <item>
      <title>Glam Up My Markup: Cricket League!</title>
      <dc:creator>Suman Sourabh</dc:creator>
      <pubDate>Sun, 04 Aug 2024 09:19:15 +0000</pubDate>
      <link>https://dev.to/sumansourabh48/glam-up-my-markup-cricket-league-201c</link>
      <guid>https://dev.to/sumansourabh48/glam-up-my-markup-cricket-league-201c</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for &lt;a href="https://dev.to/challenges/frontend-2024-07-24"&gt;Frontend Challenge v24.07.24&lt;/a&gt;, Glam Up My Markup: Recreation&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;Here I have built a landing page for the New York Recreational Cricket League by transforming a basic HTML template into something that is visually related to Cricket. I used some CSS and basic JavaScript for interactivity.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/sumansourabh14/embed/VwJbQBJ?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Journey
&lt;/h2&gt;

&lt;p&gt;I played with CSS gradients to add a visual of sky (in the header) and grass (in the footer). I included a few icons related to Cricket as well.&lt;/p&gt;

&lt;p&gt;For enhancing the user experience, I included a "Go to top" button, which when clicked, goes to the top of the page. It is fixed on the bottom right of the screen.&lt;/p&gt;

&lt;p&gt;Looking forward to more frontend challenges.&lt;/p&gt;

&lt;p&gt;Thanks for reading this post!&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>frontendchallenge</category>
      <category>css</category>
      <category>javascript</category>
    </item>
    <item>
      <title>2024 Guide to Infinite Scrolling in React/Next.js</title>
      <dc:creator>Suman Sourabh</dc:creator>
      <pubDate>Wed, 05 Jun 2024 17:00:43 +0000</pubDate>
      <link>https://dev.to/sumansourabh48/2024-guide-to-infinite-scrolling-in-reactnextjs-48a1</link>
      <guid>https://dev.to/sumansourabh48/2024-guide-to-infinite-scrolling-in-reactnextjs-48a1</guid>
      <description>&lt;p&gt;Ever saw how posts keep on displaying on the feed section of X (Twitter) or Instagram if you keep scrolling down?&lt;/p&gt;

&lt;p&gt;That “thing” is called infinite scroll.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Infinite Scrolling?
&lt;/h2&gt;

&lt;p&gt;Infinite scrolling is a technique or approach in web development where more resources are fetched and displayed on the page as the user scrolls down.&lt;/p&gt;

&lt;p&gt;For example, in social media platforms such as X (Twitter), if you scroll down in the feed, more posts will display to you.&lt;/p&gt;

&lt;p&gt;This approach is helpful when you have a lot of resources to show on the page and you do not want to fetch them all at once and slow down the application.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to use it in React/Next.js?
&lt;/h2&gt;

&lt;p&gt;Of course, you can build your own infinite scrolling component from scratch but in many cases, it is better to use a library.&lt;/p&gt;

&lt;p&gt;On &lt;a href="https://libertas-vert.vercel.app/"&gt;Libertas&lt;/a&gt;, I have used a popular library called react-infinite-scroll-component.&lt;/p&gt;

&lt;p&gt;This library has an inbuilt component which does the behaviour of infinite scrolling for us. We just have to dump our code of fetching multiple items inside this code.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Feedback is appreciated about this approach.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Understanding the Scenario
&lt;/h2&gt;

&lt;p&gt;I have a &lt;a href="https://libertas-vert.vercel.app/feed"&gt;feed page&lt;/a&gt; on Libertas where I show all the posts that the users have created. It is just like how different items are displayed on the feed page on Reddit, X, Medium, Nike and other such platforms.&lt;/p&gt;

&lt;p&gt;Our aim is to fetch some posts/items when the page loads fully. When the user scrolls to the bottom of the page or the last item that was fetched when the page loaded, we trigger a GET request to fetch more posts.&lt;/p&gt;

&lt;p&gt;This process repeats until all the items are fetched, which may not be possible if the items are huge in numbers (&amp;gt;500 items). Hence, the name “Infinite scroll”! Users will get exhausted, won’t they?&lt;/p&gt;

&lt;h2&gt;
  
  
  Steps to Implement &lt;code&gt;react-infinite-scroll-component&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Below are the steps where I mention how I added this component into Libertas.&lt;/p&gt;

&lt;h3&gt;
  
  
  Install the package
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;For npm:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i react-infinite-scroll-component
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;For yarn:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn add react-infinite-scroll-component
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Copy and paste the below code for infinite scroll in Libertas&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;InfiniteScroll
  dataLength={items.length} //This is important field to render the next data
  next={fetchData}
  hasMore={true}
  loader={&amp;lt;h4&amp;gt;Loading...&amp;lt;/h4&amp;gt;}
  endMessage={
    &amp;lt;p style={{ textAlign: 'center' }}&amp;gt;
      &amp;lt;b&amp;gt;Yay! You have seen it all&amp;lt;/b&amp;gt;
    &amp;lt;/p&amp;gt;
  }
&amp;gt;
  {items}
&amp;lt;/InfiniteScroll&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Understanding the props
&lt;/h3&gt;

&lt;p&gt;According to &lt;code&gt;react-infinite-scroll-component&lt;/code&gt; &lt;a href="https://github.com/ankeetmaini/react-infinite-scroll-component"&gt;GitHub page&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;dataLength:&lt;/strong&gt; set the length of the data. This will unlock the subsequent calls to next.&lt;br&gt;
&lt;strong&gt;next:&lt;/strong&gt; a function which must be called after reaching the bottom. It must trigger some sort of action which fetches the next data. The data is passed as children to the &lt;code&gt;InfiniteScroll&lt;/code&gt;component and the data should contain previous items too. e.g. Initial &lt;code&gt;data = [1, 2, 3]&lt;/code&gt; and then next load of data should be &lt;code&gt;[1, 2, 3, 4, 5, 6]&lt;/code&gt;.&lt;br&gt;
&lt;strong&gt;hasMore:&lt;/strong&gt; it tells the &lt;code&gt;InfiniteScroll&lt;/code&gt; component on whether to call next function on reaching the bottom and shows an &lt;code&gt;endMessage&lt;/code&gt; to the user&lt;br&gt;
&lt;strong&gt;loader:&lt;/strong&gt; you can send a loader component to show while the component waits for the next load of data. e.g. &lt;code&gt;&amp;lt;h3&amp;gt;Loading…&amp;lt;/h3&amp;gt;&lt;/code&gt; or any fancy loader element&lt;br&gt;
&lt;strong&gt;endMessage:&lt;/strong&gt; this message is shown to the user when he has seen all the records which means he’s at the bottom and hasMore is false&lt;br&gt;
&lt;strong&gt;items:&lt;/strong&gt; The list of items to be fetched and displayed on the page. In case of Libertas, the &lt;code&gt;{items}&lt;/code&gt; are the list of posts created by users.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Further Steps:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Fetch some posts when the page loads&lt;/li&gt;
&lt;li&gt;Display the list of posts on the page&lt;/li&gt;
&lt;li&gt;Make a slight change on the API GET request (Backend) to fetch the next list of posts&lt;/li&gt;
&lt;li&gt;Fetch the next list of posts on the frontend&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Final code:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const [posts, setPosts] = useState([]);
  const [count, setCount] = useState(4);
  const [currentCount, setCurrentCount] = useState(null);
  const [total, setTotal] = useState(null);

  const fetchPosts = async () =&amp;gt; {
    const data = await fetchAllPosts(count);
    console.log(data?.data?.data);

    setPosts(data?.data?.data);
    setCurrentCount(data?.data?.currentLength);
    setTotal(data?.data?.total);
    setCount(count + 2);
  };

  useEffect(() =&amp;gt; {
    fetchPosts();
  }, []);

  return (
    &amp;lt;Stack&amp;gt;
        &amp;lt;InfiniteScroll
          dataLength={posts?.length} //This is important field to render the next data
          next={fetchPosts}
          hasMore={currentCount !== total}
          loader={&amp;lt;h4&amp;gt;Loading...&amp;lt;/h4&amp;gt;}
          endMessage={
            &amp;lt;p style={{ textAlign: "center" }}&amp;gt;
              &amp;lt;b&amp;gt;Yay! You have seen it all&amp;lt;/b&amp;gt;
            &amp;lt;/p&amp;gt;
          }
        &amp;gt;
          {posts.map((post) =&amp;gt; (
            &amp;lt;PostComponent
              key={post._id}
              post={post}
              id={post._id}
              handleUpvote={() =&amp;gt; handleVote(upvoteAPost, post._id)}
              handleDownvote={() =&amp;gt; handleVote(downvoteAPost, post._id)}
              individualView={false}
            /&amp;gt;
          ))}
        &amp;lt;/InfiniteScroll&amp;gt;
      &amp;lt;/Stack&amp;gt;
  );
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Breakdown of the code
&lt;/h3&gt;

&lt;p&gt;I created a GET request named &lt;code&gt;fetchAllPosts&lt;/code&gt;which fetches 4 posts when the page loads. I used map function to list all the posts inside the &lt;code&gt;InfiniteScroll&lt;/code&gt;component.&lt;/p&gt;

&lt;p&gt;In order to fetch the next set of posts, I had to make a slight change in the API of the request (written in Node.js) where I fetch the posts. That change was adding a count or a number that will tell me how many posts to fetch. When the user scrolls down the web page, those number of posts will be fetched from the database and displayed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// @desc    Get all the posts
// @route   GET /api/user/posts
// @access  Public
const getAllPosts = asyncHandler(async (req, res, next) =&amp;gt; {
  const { count } = req.query;

  const posts = await PostModel.find();
  const postsToDisplay = posts.reverse().slice(0, count);

  res.status(200).json({
    success: true,
    total: posts.length,
    currentLength: postsToDisplay.length,
    data: postsToDisplay,
  });
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I added a count variable which comes from the query in the URL just like this: &lt;code&gt;api/v1/posts?count=4&lt;/code&gt;. This fetches only 4 posts.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Now, things were easier. Time to add the frontend code to fetch the next set of posts.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const [posts, setPosts] = useState([]);
  const [count, setCount] = useState(4);
  const [currentCount, setCurrentCount] = useState(null);
  const [total, setTotal] = useState(null);

  const fetchPosts = async () =&amp;gt; {
    const data = await fetchAllPosts(count);

    setPosts(data?.data?.data);
    setCurrentCount(data?.data?.currentLength);
    setTotal(data?.data?.total);
    setCount(count + 2);
  };
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above code first fetches 4 posts (coming from the initial value of the count state variable).&lt;/p&gt;

&lt;p&gt;It also sets the current count or the current length of the posts which will be 4 on the first fetch.&lt;/p&gt;

&lt;p&gt;The value of total no. of posts is also set as it is being returned in the API response.&lt;/p&gt;

&lt;p&gt;Lastly, the value of count updates to 6, which will be used for the next fetch function call.&lt;/p&gt;

&lt;p&gt;The above values are used in the &lt;code&gt;InfiniteScroll&lt;/code&gt;component below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;InfiniteScroll
  dataLength={posts?.length} //This is important field to render the next data
  next={fetchPosts}
  hasMore={currentCount !== total}
  loader={&amp;lt;h4&amp;gt;Loading...&amp;lt;/h4&amp;gt;}
  endMessage={
    &amp;lt;p style={{ textAlign: "center" }}&amp;gt;
      &amp;lt;b&amp;gt;Yay! You have seen it all&amp;lt;/b&amp;gt;
    &amp;lt;/p&amp;gt;
  }
&amp;gt;
  {posts.map((post) =&amp;gt; (
    &amp;lt;PostComponent
      key={post._id}
      post={post}
      id={post._id}
      handleUpvote={() =&amp;gt; handleVote(upvoteAPost, post._id)}
      handleDownvote={() =&amp;gt; handleVote(downvoteAPost, post._id)}
      individualView={false}
    /&amp;gt;
  ))}
&amp;lt;/InfiniteScroll&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Working of &lt;code&gt;InfiniteScroll&lt;/code&gt;component
&lt;/h3&gt;

&lt;p&gt;In the above code, the list of posts are displayed. After this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The value of &lt;code&gt;dataLength&lt;/code&gt;gets assigned to the number of posts fetched for the first time.&lt;/li&gt;
&lt;li&gt;When the user scrolls down, the &lt;code&gt;hasMore&lt;/code&gt;prop comes into action.
&lt;code&gt;hasMore&lt;/code&gt;tells us that if it is true, initiate the function available in the next prop. In our code, when the current count or current length of the posts is not equal to the total no. of posts, call the &lt;code&gt;fetchPosts&lt;/code&gt;function.&lt;/li&gt;
&lt;li&gt;Then &lt;code&gt;fetchPosts&lt;/code&gt;is called with the updated count value of 6, then 6 posts are fetched and the value of posts array is updated. The value of &lt;code&gt;dataLength&lt;/code&gt;is also updated.&lt;/li&gt;
&lt;li&gt;If all the posts are not fetched, the content inside the loader prop is displayed after the latest post. Ideally, this can be a &lt;a href="https://www.smashingmagazine.com/2020/04/skeleton-screens-react/"&gt;skeleton component&lt;/a&gt; or a loading text/animation.&lt;/li&gt;
&lt;li&gt;If &lt;code&gt;hasMore&lt;/code&gt;is false or in other words, all the posts are fetched from the database, the element inside the &lt;code&gt;endMessage&lt;/code&gt;prop is displayed after the last post.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Infinite scroll&lt;/strong&gt; is a good approach to make a website perform a bit better but like everything in tech, this approach is not for every website. It mostly depends on the type of platform and the type of users (target audience).&lt;/p&gt;

&lt;p&gt;I added this to &lt;a href="https://medium.com/@sumsourabh14/reddit-alternative-heres-what-i-am-building-sort-of-2b8044842952"&gt;Libertas&lt;/a&gt;, the online discussion platform built with Next.js, because the users will create multiple posts and it will be a headache/nightmare to render everything at once on a single web page. Wouldn’t it?&lt;/p&gt;

&lt;h2&gt;
  
  
  Wondering what is Libertas?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Libertas is an online discussion website&lt;/strong&gt; for users where they can just discuss. &lt;strong&gt;Discuss freely. No rules, no moderators.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can just look at the posts that the users have created or if you feel hooked, you can sign up and start creating! You can upvote/downvote posts and comment on them. If you forget your password, there is an option reset it too!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://libertas-vert.vercel.app/"&gt;Try Libertas here.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can let me know on &lt;a href="https://www.linkedin.com/in/sumansourabh14/"&gt;LinkedIn&lt;/a&gt; or &lt;a href="https://twitter.com/sumansourabh48"&gt;Twitter&lt;/a&gt; if you want any feature or would like to have a suggestion.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Any feedback is deeply appreciated!&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>tutorial</category>
      <category>react</category>
      <category>frontend</category>
    </item>
    <item>
      <title>How to Display a PDF in Next.js Using React PDF Viewer?</title>
      <dc:creator>Suman Sourabh</dc:creator>
      <pubDate>Sun, 02 Jun 2024 19:20:02 +0000</pubDate>
      <link>https://dev.to/sumansourabh48/how-to-display-a-pdf-in-nextjs-using-react-pdf-viewer-23eg</link>
      <guid>https://dev.to/sumansourabh48/how-to-display-a-pdf-in-nextjs-using-react-pdf-viewer-23eg</guid>
      <description>&lt;p&gt;This blog talks about how you can display a PDF file in your Next.js app.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Create a Next.js project with the following command
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx create-next-app@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Follow the instructions and a new Next.js project will be created.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Run the Next.js project
&lt;/h3&gt;

&lt;p&gt;Type the following command on the terminal.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open a web browser like Chrome, and go to &lt;a href="http://localhost:3000"&gt;http://localhost:3000&lt;/a&gt;. You will see your new Next.js project running.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8m87ns6j7vciwsedksg8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8m87ns6j7vciwsedksg8.png" alt="Next.js app" width="800" height="399"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, we will use the React PDF viewer component to display the PDF file on the page.&lt;/p&gt;

&lt;p&gt;You can refer this documentation to get started: &lt;a href="https://react-pdf-viewer.dev/"&gt;Getting started — React PDF Viewer&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Steps to use React PDF Viewer:
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Install a few packages
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install pdfjs-dist@3.4.120
npm install @react-pdf-viewer/core@3.12.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Copy the original code
&lt;/h3&gt;

&lt;p&gt;Go to &lt;a href="https://react-pdf-viewer.dev/docs/basic-usage/"&gt;this page&lt;/a&gt; and paste the code on &lt;code&gt;page.js&lt;/code&gt; inside the project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Viewer, Worker } from "@react-pdf-viewer/core";

export default function Home() {
  return (
    &amp;lt;main&amp;gt;
      &amp;lt;Worker workerUrl="https://unpkg.com/pdfjs-dist@2.15.349/build/pdf.worker.js"&amp;gt;
        &amp;lt;div&amp;gt;
          &amp;lt;Viewer fileUrl="./sample-pdf-file.pdf" /&amp;gt;
        &amp;lt;/div&amp;gt;
      &amp;lt;/Worker&amp;gt;
    &amp;lt;/main&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Run the project
&lt;/h3&gt;

&lt;p&gt;Most likely, you will encounter an error.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F54gg6x4xoh30reogrlka.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F54gg6x4xoh30reogrlka.png" alt="runtime error on nextjs" width="800" height="180"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is a pretty common error in Next.js about the usage of client components.&lt;/p&gt;

&lt;p&gt;Basically, it just says that React PDF Viewer component uses some code that can only work on client components and not the server components.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Fix the server error
&lt;/h3&gt;

&lt;p&gt;What you have to do is just type &lt;code&gt;“use client”&lt;/code&gt; on top of your page.&lt;/p&gt;

&lt;p&gt;Now, the overall code becomes this&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6ms5zf4ujhjauwkjshfo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6ms5zf4ujhjauwkjshfo.png" alt="screenshot of the code with use client at the top" width="800" height="322"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Run the project again
&lt;/h3&gt;

&lt;p&gt;Now you will encounter another error.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzf512chwvfjrzn2o9t5u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzf512chwvfjrzn2o9t5u.png" alt="Image description" width="693" height="41"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This error comes when there is a mismatch in the versions of the worker and the &lt;code&gt;pdfjs-dist&lt;/code&gt; package.&lt;/p&gt;

&lt;p&gt;To fix this, just change the version of &lt;code&gt;pdfjs-dist&lt;/code&gt; inside the &lt;code&gt;workerUrl&lt;/code&gt; to &lt;code&gt;3.4.120&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;Worker workerUrl="https://unpkg.com/pdfjs-dist@3.4.120/build/pdf.worker.js"&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you run now, you will see the PDF being displayed on the page.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv02z3gtlzpt6tfa3532m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv02z3gtlzpt6tfa3532m.png" alt="Image description" width="800" height="401"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But hold on! There’s something weird.&lt;/p&gt;

&lt;p&gt;Look at the right side of the page, there’s a black background which looks odd.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Copy styles
&lt;/h3&gt;

&lt;p&gt;To make the styling correct, copy and paste the styles from &lt;a href="https://github.com/react-pdf-viewer/starter/tree/main/nextjs"&gt;this page&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Import the styles provided by the react-pdf-viewer packages
import "@react-pdf-viewer/default-layout/lib/styles/index.css";
import "@react-pdf-viewer/core/lib/styles/index.css";
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, you will encounter another error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Module not found: Error: Can't resolve '@react-pdf-viewer/default-layout/lib/styles/index.css'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To resolve this, install this package:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install @react-pdf-viewer/default-layout
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, final dependencies are&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcjremskis3jpt2h3d21v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcjremskis3jpt2h3d21v.png" alt="Image description" width="629" height="241"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  7. Run the project for the final time
&lt;/h3&gt;

&lt;p&gt;Upon running the project now, the PDF will be displayed on the full page.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftp1jvuiya9lv67g6fkf7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftp1jvuiya9lv67g6fkf7.png" alt="Image description" width="800" height="399"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Final code
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"use client";
import { Viewer, Worker } from "@react-pdf-viewer/core";
import "@react-pdf-viewer/default-layout/lib/styles/index.css";
import "@react-pdf-viewer/core/lib/styles/index.css";

export default function Home() {
  return (
    &amp;lt;main&amp;gt;
      &amp;lt;Worker workerUrl="https://unpkg.com/pdfjs-dist@3.4.120/build/pdf.worker.js"&amp;gt;
        &amp;lt;div&amp;gt;
          &amp;lt;Viewer fileUrl="./sample-pdf-file.pdf" /&amp;gt;
        &amp;lt;/div&amp;gt;
      &amp;lt;/Worker&amp;gt;
    &amp;lt;/main&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this blog post, we saw how you can display a PDF previewer on a page in Nextjs application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Read more:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://sumansourabh.in/2024-guide-to-infinite-scrolling-in-react-next-js/"&gt;2024 Guide to Infinite Scrolling in React/Next.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://sumansourabh.in/how-to-upgrade-latest-expo-react-native-version/"&gt;How to Actually Upgrade Expo and React Native Versions to Latest?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://sumansourabh.in/how-to-create-toggle-password-visibility-with-material-ui/"&gt;How to Create Toggle Password Visibility with Material UI?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>nextjs</category>
      <category>tutorial</category>
      <category>frontend</category>
    </item>
  </channel>
</rss>
