utterance / utterances

:crystal_ball: A lightweight comments widget built on GitHub issues
https://utteranc.es
MIT License
8.66k stars 567 forks source link

Utterances component render twice in Next.js(SSG) #634

Closed usernamechiho closed 1 year ago

usernamechiho commented 1 year ago
// _Components/Comment.js

import { useEffect, useRef } from 'react';

export default function Comment() {
  const commentsRef = useRef<HTMLElement | null>(null);

  useEffect(() => {
    const scriptEl = document.createElement('script');
    scriptEl.src = 'https://utteranc.es/client.js';
    scriptEl.async = true;
    scriptEl.crossOrigin = 'anonymous';
    scriptEl.setAttribute('repo', 'usernamechiho/Cobb-dev-blog');
    scriptEl.setAttribute('issue-term', 'title');
    scriptEl.setAttribute('theme', 'github-light');
    scriptEl.setAttribute('label', 'comment');

    commentsRef.current?.appendChild(scriptEl);
  }, []);

  return <section ref={commentsRef} />;
}
/* eslint-disable react/no-danger */
import axios from 'axios';
import { dateFormat } from '_Utils/Helper';
import MarkdownRenderer from '_Components/MarkdownRenderer';
import dynamic from 'next/dynamic';
import styles from './blog.module.scss';
import 'github-markdown-css/github-markdown-light.css';

const Comment = dynamic(() => import('_Components/Comment'), {
  ssr: false,
});

const Article = ({ article }: any) => {
  return (
      <div className={styles.container}>
        <div className={styles.header}>
          <p className={styles.tag}>{article.data.attributes.tag.data.attributes.tag}</p>
          <h1>{article.data.attributes.title}</h1>
          <p className={styles.publishedDate}>Published at {dateFormat(article.data.attributes.publishedAt)}</p>
        </div>
        <main className='markdown-body'>
          <MarkdownRenderer markdown={article.data.attributes.content} />
          <Comment />
        </main>
      </div>
  );
};

export async function getStaticPaths() {
  const articlePaths: any = await axios.get(`${process.env.NEXT_PUBLIC_BASE_URL}/api/articles/?populate[0]=*`);

  const paths = articlePaths.data.data.map((path: any) => ({
    params: { id: `${path.id}` },
  }));

  return { paths, fallback: false };
}

export async function getStaticProps(ctx: any) {
  const { params } = ctx;
  const { id } = params;

  const article = await axios.get(
    `${process.env.NEXT_PUBLIC_BASE_URL}/api/articles/${id}?populate[1]=tag&populate[0]=thumbnail`
  );

  return {
    props: { article: article.data },
  };
}

export default Article;

This is the code. Right now Utterances is being rendered twice.

image

I really don't know why. I've tried not using ssr: false option (also the same result).

Need some help on this.

usernamechiho commented 1 year ago

Forgot the strict mode....

alibstrd commented 7 months ago

Forgot the strict mode....

what do you mean strict mode? i do have the same problem over here

SofieTorch commented 5 months ago

@alibstrd I think usernamechiho talks about React's Strict Mode, every component that hast a hook inside is rendered twice intentionally, but this only happens in development mode, when you deploy the section appears correctly, I deployed my page in vercel and everything is working fine :)