gpt4 book ai didi

reactjs - nextjs 动态路由渲染内容不起作用

转载 作者:行者123 更新时间:2023-12-03 14:44:41 27 4
gpt4 key购买 nike

我被这个问题困扰了很多天。我正在使用 Next.js并且有 3 页。

  • 页面/index.js
  • 页面/categories.js
  • 页面/类别/[slug].js
  • categories/[slug].js正在使用 Next.js获取方法名 getServerSideProps在每个请求上运行并用于在运行时构建动态页面。 categories/[slug].js在页面上呈现动态内容,该动态内容来自 CMS,作为 API 端点的响应。动态内容只不过是一个包含带有 <script /> 的 HTML 的字符串。元素。
    CMS Response
    备注 : 要从 CMS 中获取内容,我们必须发送 POST请求 CMS凭据,例如用户名、密码和内容的页面 slug。我正在使用 axios库发送一个post请求,方法在 post.js里面文件。
    post.js :
    import axios from 'axios';

    const postCMS = async (slug) => {
    const url = `${process.env.CMS_API_URL}/render-page/`;
    let pageSlug = slug;

    // If the pageSlug is not start with `/`, then create the slug with `/`
    if (!pageSlug.startsWith('/')) {
    pageSlug = `/${pageSlug}`;
    }

    const head = {
    Accept: 'application/json',
    'Content-Type': 'application/json'
    };

    const data = JSON.stringify({
    username: process.env.CMS_API_USERNAME,
    password: process.env.CMS_API_PASSWORD,
    slug: pageSlug
    });

    try {
    const response = await axios.post(url, data, {
    headers: head
    });
    return response.data;
    } catch (e) {
    return e;
    }
    };

    export default postCMS;
    但是对于 categories/[slug].js上的渲染内容页面,我正在使用 Reactjs Prop 名称 dangerouslySetInnerHTML渲染所有包含 <script /> 的 HTML JSON 字符串中的元素。
    页面/类别/[slug].js :
    <div dangerouslySetInnerHTML={{ __html: result.html }} /> 
    内容根据每个 slug 加载良好。但是当我导航到该类别页面时,即 pages/categories/index.js .
    <Link href="/categories/[slug]" as="/categories/online-cloud-storage">
    <a>Online Cloud Storage</a>
    </Link>
    它有一个 <Link />元素,当我单击它时。
    动态内容加载正常,但动态内容包含 accordionslider他们不工作的元素。我认为 <script />这些元素不起作用。但是当我刷新页面时,它们工作正常。看到这个。
    Preview the problem
    当我设置这样的链接时,它们也可以正常工作。
    <Link href="/categories/online-cloud-storage" as="/categories/online-cloud-storage">
    <a>Online Cloud Storage</a>
    </Link>
    但是按照上面的方法设置链接后,会导致点击硬重新加载页面。但我不想要这个。一切都应该工作。当用户点击类别链接时。
    有没有办法解决这个问题 ?
    为什么单击 categories/index.js 时内容元素不起作用页 ?
    Github repo
    代码:
    页面/index.js :
    import React from 'react';
    import Link from 'next/link';

    const IndexPage = () => {
    return (
    <div>
    <Link href="/categories">
    <a>Categories</a>
    </Link>
    </div>
    );
    };

    export default IndexPage;
    页面/类别/index.js :
    import React from 'react';
    import Link from 'next/link';

    const Categories = () => {
    return (
    <div>
    <Link href="/categories/[slug]" as="/categories/online-cloud-storage">
    <a>Online Cloud Storage</a>
    </Link>
    </div>
    );
    };

    export default Categories;
    页面/类别/[slug].js :
    import React from 'react';
    import Head from 'next/head';
    import postCMS from '../../post';

    const CategoryPage = ({ result }) => {
    return (
    <>
    <Head>
    {result && <link href={result.assets.stylesheets} rel="stylesheet" />}
    </Head>
    <div>
    <h1>Category page CMS Content</h1>
    <div dangerouslySetInnerHTML={{ __html: result.html }} />
    </div>
    </>
    );
    };


    export const getServerSideProps = async (context) => {
    const categorySlug = context.query.slug;
    const result = await postCMS(categorySlug);
    return {
    props: {
    result
    }
    };
    };


    export default CategoryPage;

    最佳答案

    这里的问题是 <script>标签是 动态插入 dangerouslySetInnerHTMLinnerHTML , 不作为 HTML 5 specification 执行状态:

    script elements inserted using innerHTML do not execute when they are inserted.


    如果要插入新的 <script>页面初始渲染后的标签,您需要通过 JavaScript 的 document.createElement('script') 来完成。接口(interface)并使用 element.appendChild() 附加到 DOM以确保他们被执行。
    脚本 的原因不工作改变路线后,但他们 做工作刷新页面后绑定(bind)到 Next.js 应用程序生命周期过程。
  • 如果刷新页面,Next.js 会在服务器上预渲染整个网站,并将其作为一个整体发送回客户端。因此,网站被解析为常规静态页面,<script>标签 像往常一样执行。
  • 如果您更改路由,Next.js 不会刷新整个网站/应用程序,而只会刷新其中已更改的部分。换句话说,只有 page组件被提取,它是 动态插入现有布局替换以前的page .因此,<script>标签是 不是 执行。

  • 简单的解决方案
    通过解析 HTML 字符串并重新创建 DOM 树结构,让一些现有的库为您处理繁重的工作。这是它在 jQuery 中的外观:
    import { useEffect, useRef } from 'react';
    import $ from 'jquery';

    const CategoryPage = ({ result }) => {
    const element = useRef();
    useEffect(() => {
    $(element.current).html($(result.html));
    }, []);

    return (
    <>
    <Head>
    {result && <link href={result.assets.stylesheets} rel="stylesheet" />}
    </Head>
    <div>
    <h1>Category page CMS Content</h1>
    <div ref={element}></div>
    </div>
    </>
    );
    };

    export const getServerSideProps = async (context) => {
    /* ... */
    return { props: { result } };
    }
    更难的解决方案
    您必须找到一种方法来提取所有 <script> HTML 字符串中的标签并将它们分别添加到您的页面中。最简洁的方法是修改 API 响应以在两个单独的字符串中提供静态 HTML 和动态脚本。然后,您可以插入带有 dangerouslySetInnerHTML 的 HTML并在 JS 中添加脚本:
    const scripts = extractScriptTags(result.html);    // The hard part
    scripts.forEach((script) => {
    const scriptTag = document.createElement('script');
    scriptTag.innerText = script;
    element.current.appendChild(scriptTag);
    });

    关于reactjs - nextjs 动态路由渲染内容不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64053006/

    27 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com