skip to Main Content

I am working on a commenting feature for a blog using latest version of NextJs.
Text input collects data, and sends it to the database ‘Vercel` hosted,
and I fetch the data from the frontend successfully as expected.

However, displaying the data in the frontend behaves as expected, but if user
refreshes the page the data gets lost for some reasons (pls see attached gif) – This behavior is not
expected as data is not persistent. Is this because this is a dynamic route in a page route app or perhaps the comments are displayed in a component rather than the actual page – Can you help figure this out? Thanks in advance.

//Dynamic Route  '/pages/blog/[slug].js'

import React, { useRef, useState, useEffect } from 'react';
import { getSinglePost, getPosts } from '../../lib/posts';
import { Button } from '@nextui-org/react';
import CommentBox from '../../components/Blogs/CommentBox';
import useSWR from 'swr';
import { useSession } from "next-auth/react";


const PostPage = ({ post }) => {
    const [postContent, setPostContent] = useState({
        id: post.id,
        title: post.title,
        content: post.html
    });
    const [comments, setComments] = useState([]);
    const [newComment, setNewComment] = useState('');
    const [value, setValue] = useState(0);

    const { data: session } = useSession();


    const handleCommentChange = (event) => {
        setNewComment(event.target.value);
    };


    //Access post.id and sets it as postId, and the using `SWR` to fetch data from the database
    const postId = post.id;
    const { data: commentsData, error } = useSWR(`/api/blog/commentsystem?postId=${postId}`);

    // Update comments state when data is fetched
    useEffect(() => {
        if (commentsData) {
            setComments(commentsData);

        }
    }, [commentsData]);

    // Function to handle form submission
    const handleSubmit = async (event) => {
        event.preventDefault();

        if (newComment.trim() !== '' && session) {
            setLoading(true);

            const user = session.user;

            const commentObject = {
                articleContent: newComment,
                user: user,
                date: new Date().toLocaleString(),
            };

            const { user: articleUser, name: articleEmail } = user;
            const title = post.title;

            try {
                const response = await fetch('/api/blog/commentsystem', {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                    },
                    body: JSON.stringify({ user: articleUser, articleContent: newComment, email: articleEmail, postTitle: title, postId: postId })
                });

                if (!response.ok) {
                    throw new Error('Failed to post comment');
                }

                const responseData = await response.json();
                console.log("data from DB:", responseData);  // returns data as expected.

                setComments(prevComments => [...prevComments, responseData]);
                setNewComment('');
                setLoading(false);

            } catch (error) {
                console.error('Error posting comment:', error.message);
            }
        }
    };

    console.log("Comments data from DB:", comments);  // returns data as expected.

    return (
        <div>
           <span >
            {/* Component that displays comments takes in data set as state variable as a prop*/}
            < CommentBox comments={comments} />
            </span>
           <form onSubmit={handleSubmit}>
           <div >
            <div >
                <label htmlFor="comment" >Share your thoughts</label>
                <textarea
                    id="comment"
                    rows="4"
                    placeholder="Post comments..."
                    value={newComment}
                    onChange={handleCommentChange}
                    required
                />
            </div>
            <div >
                <button type="submit">
                    Post comment
                </button>
            </div>
            </div>
            </form>
        </div>
    );
};


//Function below gets 'post' from external api, and sets it as props
export async function getStaticPaths() {
    const allPosts = await getPosts();

    const paths = allPosts.map((post) => ({
        params: { slug: post.slug }
    }));

    return {
        paths,
        fallback: false
    };
}

export async function getStaticProps({ params }) {
    const post = await getSinglePost(params.slug);

    if (!post) {
        return {
            notFound: true
        };
    }

    return {
        props: { post }
    };
}

export async function generateMetadata({ params }) {
    const post = await getSinglePost(params.slug);
    return {
        title: post.title,
        description: post.excerpt,
        openGraph: {
            title: post.title,
            description: post.excerpt,
            images: [
                {
                    url: post.image,
                },
            ],
        },
    };
}

export default PostPage;
///////////////////////////////////
// Component
///////////////////////////////////

const CommentBox = ({ comments }) => {

    //comments is imported from the dynamic page as prop 

    console.log(comments);  // returns data as expected.
    return (
        <div>
            <div>
                {comments && comments.map((item, index) => {
                    return (
                        <div key={item.id}>
                            {Array.isArray(item.comments) && item.comments.map((comment, commentIndex) => (
                                <div key={comment.id}>
                                    {/* Render each comment */}
                                    {console.log(comment)}
                                    <div>
                                        {/* Render profile image */}
                                        <div>
                                            {/* Render comment author */}
                                            <div>
                                                <span>{comment.commentBy}</span>
                                            </div>
                                            {/* Render comment content */}
                                            <div>
                                                <p>{comment.comment}</p>
                                            </div>
                                            {/* Render posted time */}
                                        </div>
                                    </div>
                                </div>
                            ))}
                        </div>
                    );
                })}
            </div>
        </div>
    );
};

export default CommentBox;

3

Answers


  1. You can use local storage.

    What is local storage?

    Local storage is a form of data persistence that allows you store data locally on your computer while having access to those resources offline. Local storage can store large amounts of data locally without having to transfer data to a server. A benefit of using local storage is that it doesn’t have expiration date, implying that stored data can be available anytime and anywhere.

    You can create something like that:

    useEffect(
    ()=>{
    localStorage.setItem('data', data)
    },[])
    

    Then when it loads you will use localStorage.get to get the data.

    Login or Signup to reply.
  2. I would suggest you to use Cache API.

    Compared to other traditional storage mechanisms like localstorage and sessionstorage it has many advantages. I am adding a couple of them below

    1. Asynchronous operations. It will not block your main thread when it tries to read / write.
    2. More storage capacity. It will allow you to use up-to 60% of your disk space

    If you are aiming towards an offline experience as well for your app, then you can integrate a ServiceWorker too in future. Cache API is the suggested storage mechanism to be used along with a Service Worker

    Login or Signup to reply.
  3. The answer actually depends on what you want to store and the size of the same payload. Upon reading through, i anticipate you would want to retain the items or inputs made by an user and retrieve the same set once the page loads/refreshes back. There are two ways to do:

    1. LocalStorage is a good option if your cumulative data payload doesnt exceed 5MB. It can store data upto 5MB and has get() and setItem() methods to store data.
    2. If you want a production grade data retain with a bigger size context, you should look at a cache based solution. Browser based caches don’t offer much data payload but you can rely on distributed object databases like Redis or Memcached to store much bigger data sizes.
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search