Build a Next.js Interactive Web-Based Simple Blog with Comments

Written by

in

In the dynamic world of web development, creating interactive and engaging user experiences is paramount. Blogs, being a cornerstone of online content, can significantly benefit from interactivity. Imagine users not only reading your articles but also actively participating by leaving comments, sharing their thoughts, and engaging in discussions directly on your site. This tutorial guides you through building a simple, yet functional, blog with a commenting system using Next.js, a powerful React framework, perfect for beginners and intermediate developers looking to expand their skills.

Why Build a Blog with Comments?

Adding comments to your blog enhances user engagement, fosters a sense of community, and provides valuable feedback on your content. It allows for a two-way communication channel, turning passive readers into active participants. This interactive element can significantly increase your website’s dwell time, improve SEO, and build a loyal audience. Furthermore, learning how to implement such features is a valuable skill in modern web development, applicable to a wide range of projects.

What You’ll Learn

This tutorial will cover the following key areas:

  • Setting up a Next.js project.
  • Creating blog post components.
  • Implementing a commenting system (storing comments, displaying comments).
  • Styling the blog and comments using CSS modules.
  • Deploying your blog.

Prerequisites

Before you begin, ensure you have the following:

  • Basic understanding of HTML, CSS, and JavaScript.
  • Node.js and npm (or yarn) installed on your system.
  • A code editor (e.g., VS Code, Sublime Text).

Step-by-Step Guide

1. Setting Up Your Next.js Project

First, let’s create a new Next.js project. Open your terminal and run the following command:

npx create-next-app my-blog-with-comments

This command creates a new directory named my-blog-with-comments and sets up a basic Next.js project. Navigate into the project directory:

cd my-blog-with-comments

Now, start the development server:

npm run dev

Open your browser and go to http://localhost:3000 to see the default Next.js welcome page. This confirms that your project is set up correctly.

2. Creating Blog Post Components

We’ll create a simple blog post structure. Inside the pages directory, create a new file named posts/[slug].js. This will be the dynamic route for each blog post. The [slug] part indicates a dynamic segment, meaning each post will have a unique URL based on its slug (e.g., /posts/my-first-post).

Here’s a basic structure for [slug].js:

import { useRouter } from 'next/router';

function BlogPost() {
  const router = useRouter();
  const { slug } = router.query;

  // In a real application, you'd fetch the post data based on the slug
  // For this example, we'll hardcode some data.
  const post = {
    title: 'My First Blog Post',
    content: "<p>This is the content of my first blog post.</p>",
    // In a real application, you'd fetch the post data based on the slug
  };

  return (
    <div>
      <h1>{post.title}</h1>
      <div dangerouslySetInnerHTML={{ __html: post.content }} />
      <h2>Comments</h2>
      <-- Comments will go here -->
    </div>
  );
}

export default BlogPost;

In this code:

  • We import useRouter from next/router to access the dynamic route parameters.
  • router.query.slug gives us the slug of the current post.
  • The post object holds the title and content. In a real app, you would fetch this data from a database or a Markdown file based on the slug.
  • We use dangerouslySetInnerHTML to render the HTML content of the post. Be cautious when using this; always sanitize your input to prevent XSS attacks.

3. Creating a Simple Home Page

Let’s create a simple home page that lists our blog posts. Edit the pages/index.js file.

import Link from 'next/link';

function HomePage() {
  const posts = [
    {
      title: 'My First Blog Post',
      slug: 'my-first-post',
    },
    {
      title: 'Another Great Post',
      slug: 'another-great-post',
    },
  ];

  return (
    <div>
      <h1>My Blog</h1>
      <ul>
        {posts.map((post) => (
          <li key={post.slug}>
            <Link href={`/posts/${post.slug}`}>
              <a>{post.title}</a>
            </Link>
          </li>
        ))}
      </ul>
    </div>
  );
}

export default HomePage;

In this code:

  • We import Link from next/link for client-side navigation.
  • The posts array holds the title and slug for each post.
  • We use Link to create links to each post’s page.
  • The href prop in Link uses a template literal to construct the URL based on the slug (e.g., /posts/my-first-post).

4. Implementing the Commenting System

Now, let’s add the commenting functionality. We’ll start with a basic form for users to submit comments and then display them. We will use a simple in-memory array to store comments for this example. In a real-world application, you’d use a database (e.g., MongoDB, PostgreSQL) to store the comments.

First, add the following code inside the BlogPost component, within the <div> that wraps the content:

  const [comments, setComments] = React.useState([]);
  const [commentText, setCommentText] = React.useState('');

  React.useEffect(() => {
    // In a real application, you'd fetch comments from a database here
    // For this example, we'll hardcode some data.
    setComments([
      {
        author: 'John Doe',
        text: 'Great post!',
      },
      {
        author: 'Jane Smith',
        text: 'I learned a lot.',
      },
    ]);
  }, []);

  const handleCommentSubmit = (event) => {
    event.preventDefault();
    if (commentText.trim() === '') return;
    const newComment = {
      author: 'Guest',
      text: commentText,
    };
    setComments([...comments, newComment]);
    setCommentText('');
  };

Next, add the comment form and display comments inside the BlogPost component, after the closing </div> for the post content, but before the closing </div> of the entire component:


      <h2>Comments</h2>
      <ul>
        {comments.map((comment, index) => (
          <li key={index}>
            <strong>{comment.author}: </strong> {comment.text}
          </li>
        ))}
      </ul>
      <form onSubmit={handleCommentSubmit}>
        <textarea
          value={commentText}
          onChange={(e) => setCommentText(e.target.value)}
          placeholder="Add a comment..."
        />
        <button type="submit">Submit</button>
      </form>

In this code:

  • We use the useState hook to manage the comments array and the input commentText.
  • The useEffect hook is used to mimic fetching comments from a database (in a real app).
  • handleCommentSubmit adds a new comment to the comments array when the form is submitted.
  • We render the comments using the map method.
  • The form allows users to type and submit their comments.

5. Styling with CSS Modules

To style your blog, let’s use CSS Modules. Create a file named [slug].module.css in the same directory as your [slug].js file (i.e., pages/posts).

Add some basic styles to the CSS module. For example:

.post {
  margin-bottom: 20px;
}

.comment {
  margin-bottom: 10px;
  padding: 10px;
  border: 1px solid #ccc;
  border-radius: 4px;
}

.comment form {
  margin-top: 20px;
}

.comment textarea {
  width: 100%;
  padding: 10px;
  margin-bottom: 10px;
  border: 1px solid #ccc;
  border-radius: 4px;
}

.comment button {
  padding: 10px 20px;
  background-color: #0070f3;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}

Import the CSS module into your [slug].js file:

import styles from './[slug].module.css';

Then, apply the styles to your components:


    <div className={styles.post}>
      <h1>{post.title}</h1>
      <div dangerouslySetInnerHTML={{ __html: post.content }} />
      <h2>Comments</h2>
      <ul>
        {comments.map((comment, index) => (
          <li key={index} className={styles.comment}>
            <strong>{comment.author}: </strong> {comment.text}
          </li>
        ))}
      </ul>
      <form onSubmit={handleCommentSubmit} className={styles.commentForm}>
        <textarea
          value={commentText}
          onChange={(e) => setCommentText(e.target.value)}
          placeholder="Add a comment..."
        />
        <button type="submit">Submit</button>
      </form>
    </div>

Now, your blog posts and comments will be styled according to the CSS module you created.

6. Handling Comments in a Real Application

The current implementation stores comments in an in-memory array. This is fine for demonstration but not suitable for a real-world application. Here’s how you’d handle comments in a real application:

  • Database: Use a database like MongoDB, PostgreSQL, or Firebase to store comments.
  • API Routes: Create API routes in your Next.js project (e.g., /api/comments) to handle comment creation, retrieval, and deletion.
  • Server-Side Rendering (SSR) or Static Site Generation (SSG): Fetch comments from the database on the server-side for better SEO and performance. You can use getServerSideProps or getStaticProps in your [slug].js file.
  • Authentication: Implement user authentication to allow users to log in and post comments under their usernames.
  • Sanitization: Always sanitize user input to prevent XSS attacks.

Example of a basic API route (/api/comments) using a hypothetical database interaction function (not a complete example):

// pages/api/comments.js

import { addCommentToDatabase, getCommentsForPost } from '../../utils/database'; // Hypothetical

export default async function handler(req, res) {
  if (req.method === 'POST') {
    try {
      const { postId, author, text } = req.body;
      await addCommentToDatabase(postId, author, text);
      res.status(201).json({ message: 'Comment added' });
    } catch (error) {
      console.error(error);
      res.status(500).json({ message: 'Failed to add comment' });
    }
  } else if (req.method === 'GET') {
    try {
      const { postId } = req.query;
      const comments = await getCommentsForPost(postId);
      res.status(200).json(comments);
    } catch (error) {
      console.error(error);
      res.status(500).json({ message: 'Failed to retrieve comments' });
    }
  } else {
    res.status(405).json({ message: 'Method Not Allowed' });
  }
}

Remember to handle errors and input validation in your API routes.

7. Deploying Your Blog

Next.js is designed for easy deployment. You can deploy your blog to various platforms, including:

  • Vercel: Vercel is the easiest option, as it’s the platform created by the Next.js team. It provides seamless deployment and hosting. Simply push your code to a Git repository (e.g., GitHub, GitLab, Bitbucket), and Vercel will automatically deploy your application.
  • Netlify: Another popular platform for deploying web applications. It also offers automated deployments from Git repositories.
  • Other Platforms: You can deploy to platforms like AWS, Google Cloud, or Azure, but you’ll need to configure the deployment process manually.

For Vercel, simply import your Git repository, and Vercel will handle the rest. For Netlify, connect your Git repository and configure the build command (usually npm run build or yarn build) and the publish directory (usually .next).

Common Mistakes and How to Fix Them

Here are some common mistakes and how to avoid them:

  • Incorrect File Paths: Double-check your file paths, especially when importing components and CSS modules.
  • Missing Dependencies: Make sure you’ve installed all the required dependencies (e.g., using npm install or yarn install).
  • Syntax Errors: Carefully review your code for syntax errors, especially in JavaScript and JSX. Use a code editor with syntax highlighting and linting to catch errors early.
  • Incorrect State Management: When updating state, always use the correct methods (e.g., setComments([...comments, newComment]) to avoid unexpected behavior.
  • XSS Vulnerabilities: Always sanitize user input before displaying it to prevent cross-site scripting (XSS) attacks.
  • Network Errors: When fetching data from an API, handle network errors gracefully (e.g., display an error message to the user).

Key Takeaways

This tutorial demonstrated how to build a basic blog with a commenting system using Next.js. You learned how to set up a Next.js project, create blog post components, implement a commenting system, style your blog using CSS modules, and deploy your application. Remember to consider database integration, API routes, and user authentication for a real-world application.

FAQ

  1. How do I store comments in a real application?

    Use a database such as MongoDB, PostgreSQL, or Firebase to store your comments. Create API routes to handle comment creation, retrieval, and deletion.

  2. How do I handle user authentication?

    Implement user authentication using libraries like NextAuth.js or Firebase Authentication. This allows users to log in and post comments under their usernames.

  3. How do I prevent XSS attacks?

    Always sanitize user input before displaying it. Use libraries like DOMPurify to clean HTML input and prevent malicious scripts from running.

  4. Can I use Markdown for blog posts?

    Yes, you can use a Markdown parser library (e.g., marked, remark) to render Markdown content into HTML. This allows you to write blog posts in Markdown format.

  5. How do I improve SEO?

    Use descriptive titles and meta descriptions, optimize your content for relevant keywords, and build internal and external links. Consider using server-side rendering (SSR) or static site generation (SSG) for better SEO performance.

Building a blog with interactive features like comments is a rewarding project that combines front-end and back-end development principles. By following this tutorial, you’ve taken a significant step towards creating dynamic and engaging web applications with Next.js. As you continue to develop your skills, remember that the most important thing is to experiment, learn from your mistakes, and keep building. The possibilities in web development are vast, and with each project, you will deepen your understanding and expand your capabilities. The ability to create interactive experiences that connect users with your content is a powerful skill, and this blog, with its commenting system, is a testament to the power of that connection.