Next.js 重新加载脚本标签

问题描述 投票:0回答:2

我正在尝试将第 3 方评论脚本嵌入到我的 next.js 中,例如。 (disqus,remark42,hyvor)但不幸的是,它仅在第一次加载时加载,我必须再次重新加载页面才能显示嵌入的第3方脚本,但它是反应/下一步的反模式。因为当您通过链接组件导航到另一个页面时,next.js 不会重新加载,所以我正在寻找一种解决方案,仅重新加载脚本组件本身,以便我的评论小部件出现在网站的每个文章页面上。

代码:

export const getStaticPaths: GetStaticPaths = async () => {
  const data = await getArticles();

  const paths = data.map((article) => ({
    params: {
      slug: article?.slug,
    },
  }));

  return {
    paths,
    fallback: true,
  };
};

export const getStaticProps = async ({
  params,
}: GetStaticPropsContext<{ slug: string }>) => {
  const article = await getArticleByProp("slug", params!.slug);

  return {
    props: {
      article: article[0],
    },
    notFound: article.length === 0,
    revalidate: 60,
  };
};

const ArticlePage = ({
  article,
}: InferGetStaticPropsType<typeof getStaticProps>) => {
  const router = useRouter();
  const articleDate = useFormattedDate(
    article?.createdAt ? new Date(article.createdAt) : new Date(),
    "distance"
  );

  if (router.isFallback) {
    return <div>Loading...</div>;
  }

  return (
    <Container>
      <SEOHeader
        title={article?.title}
        author={article?.author}
        description={article?.excerpt}
        ogImage={article?.featuredImage}
        canonical={article?.slug}
      />
      <Wrapper>
        <ArticleWrapper>
          <ArticleHeader>
            <small className="category">{article?.category}</small>
            <h1 className="title">{article?.title}</h1>
            <p className="contributor">
              <span>
                By <strong> {article?.author}</strong> <br />
              </span>
            </p>
            <div className="date">
              <Clock size={18} />{" "}
              <span>{article?.createdAt ? articleDate : "N/A"}</span>
            </div>
            <button className="share">
              <Share size={24} />
            </button>
          </ArticleHeader>
          <ArticleBody>
            {!!article?.featuredImage && (
              <Featured>
                <Image
                  src={article.featuredImage}
                  layout="responsive"
                  width={1920}
                  height={1080}
                  alt="Featured article image"
                />
              </Featured>
            )}
            <ArticleExcerpt>{article?.excerpt}</ArticleExcerpt>
            <ArticleMdx>{article?.body}</ArticleMdx>
          </ArticleBody>
          <div id="remark42">{""}</div>

          {/* <Script id="remark42-script" strategy="afterInteractive">
            {`
              var remark_config = {
                host: "http://localhost:5010",
                site_id: "mysite",
                show_email_subscription: false,
                url: "${process.env.BASE_URL + router.asPath}"
              }
              
              !(function (e, n) {
                for (var o = 0; o < e.length; o++) {
                  var r = n.createElement("script"),
                    c = ".js",
                    d = n.head || n.body;
                  "noModule" in r ? ((r.type = "module"), (c = ".mjs")) : (r.async = !0),
                    (r.defer = !0),
                    (r.src = remark_config.host + "/web/" + e[o] + c),
                    d.appendChild(r);
                }
              })(remark_config.components || ["embed"], document);
            `}
          </Script> */}

          {/* <div id="hyvor-talk-view"></div>
          <Script id="hyvor-script">
            {`
                  var HYVOR_TALK_WEBSITE = 7527;
                  var HYVOR_TALK_CONFIG = {
                      url: "${process.env.BASE_URL + router.asPath}",
                      id: "${article?.id}",
                  };
            `}
          </Script>
          <Script
            async
            src="//talk.hyvor.com/web-api/embed.js"
            strategy="lazyOnload"
            onLoad={() =>
              console.log(
                `script loaded correctly, window.FB has been populated`
              )
            }
          /> */}

          {/* <Discussion id={article?.id} title={article?.title} /> */}

          <Script id="remark42-test">{`
          const remark_config = {
            host: 'https://demo.remark42.com',
            site_id: 'remark',
          };
          window.remark_config = remark_config;
          !function(e,n){for(var o=0;o<e.length;o++){var r=n.createElement("script"),c=".js",d=n.head||n.body;"noModule"in r?(r.type="module",c=".mjs"):r.async=!0,r.defer=!0,r.src=remark_config.host+"/web/"+e[o]+c,d.appendChild(r)}}(remark_config.components||["embed"],document);
          `}</Script>
        </ArticleWrapper>
        <Recommended>
          <h2>Recommended</h2>
          <ArticleCard card={article} variant="slim" />
          <ArticleCard card={article} variant="slim" />
          <ArticleCard card={article} variant="slim" />
          <ArticleCard card={article} variant="slim" />
        </Recommended>
      </Wrapper>
    </Container>
  );
};

export default ArticlePage;
javascript next.js disqus remark42
2个回答
1
投票

也许这有助于解决类似的问题:

next/script 提供了更新的

onReady
属性,对于处理第三方地图、小部件等非常有用。

您可以在脚本首次加载时的加载事件之后执行代码,然后使用

onReady
属性重新挂载每个后续组件后执行代码。

文档中的代码示例:

      <Script
        id="google-maps"
        src="https://maps.googleapis.com/maps/api/js"
        onReady={() => {
          new google.maps.Map(mapRef.current, {
            center: { lat: -34.397, lng: 150.644 },
            zoom: 8,
          })
        }}
      />

0
投票

“next/script”中的脚本组件的工作方式与您在问题中提到的方式相同,即它只会在您登陆页面或重新加载脚本时加载脚本,之后脚本将被缓存并且不会在页面之间导航时重新加载。

因此,为了实现在来回导航时重新加载脚本的要求,我们需要使用 Vanilla JS 和上下文引用进行一些自定义调整。

请参考以下代码,并根据要求在您的代码中进行相应调整 -

export default function LoyaltyRewards(): JSX.Element | null {
    const socialAnnexRef = useRef<HTMLDivElement>(null)

    const script = `
        // Whatever script you want to inject
        <script id="social-annex">
            var siteID = '${siteId}';
            var sa_emailid = '${sAEmailId}';
            var token = '${token}';
            var sa_uni = sa_uni || []; sa_uni.push(['sa_pg', '5']);
            (function () {
                function sa_async_load () {
                    var sa = document.createElement('script');
                    sa.type = 'text/javascript';
                    sa.async = true; sa.src="https://cdn.socialannexuat.com/partner/${siteId}/universal.js";
                    var sax = document.getElementsByTagName('script')[0]; sax.parentNode.insertBefore(sa, sax);
                }
                sa_async_load();
            })();
        </script>
    `

    useEffect(() => {
        /* Clear out the loaded script's on component's un-mount */
        return () => {
            document.getElementById('social-annex')?.remove()
            document.getElementById('sa_load_loader')?.remove()
            document.getElementById('socialannex-s15dasboard')?.remove()
            document.getElementById('social-annex-universal')?.remove()
        }

        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [])

    useEffect(() => {
        if (siteId) {
            // creates a document range (grouping of nodes in the document). In this case, we instantiate it as empty, on purpose
            const range = document.createRange()
            // creates a mini-document (lightweight version), in our range with our script in it
            const documentFragment = range.createContextualFragment(script)
            // appends it on the same level of annex div - so that it renders in the correct location
            socialAnnexRef.current?.appendChild(documentFragment)
        }
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [siteId])

    return (
        <div className="mt-8" ref={socialAnnexRef}>
            <div id="socialannex_dashboard" />
        </div>
    )
}

希望这对您或其他人将来有所帮助。谢谢!

快乐编码:-)

© www.soinside.com 2019 - 2024. All rights reserved.