如何使用Next / Head渲染脚本

时间:2020-03-29 18:57:38

标签: javascript reactjs next.js

据我从SO question所了解的,我可以使用next / head将脚本标签嵌入React / Next JS应用程序的组件中。所以,我这样处理:

import React, { Component } from "react";
...
import Head from "next/head";
export const Lead = props => {
  return (
...
        <Head>
          <script
            class="3758abc"
            type="text/javascript"
            src="https://cdn2.fake.com/Scripts/embed-button.min.js"
            data-encoded="1234sdkljfeiASD9A"
          ></script>
        </Head>
...
  );
};

很遗憾,没有任何显示。我不知道我是否在这里缺少明显的东西... 我正在使用Next 9.1.7。

我的_app.js看起来像这样:


import App, { Container } from "next/app";
import Page from "../components/Page";
import { ApolloProvider } from "react-apollo";
import withData from "../lib/withData";

class MyApp extends App {
  static async getInitialProps({ Component, ctx }) {
    let pageProps = {};
    if (Component.getInitialProps) {
      pageProps = await Component.getInitialProps(ctx);
    }
    // this exposes the query to the user
    pageProps.query = ctx.query;
    return { pageProps };
  }
  render() {
    const { Component, apollo, pageProps } = this.props;

    return (
      // <Container>
      <ApolloProvider client={apollo}>
        <Page>
          <Component {...pageProps} />
        </Page>
      </ApolloProvider>
      // </Container>
    );
  }
}

export default withData(MyApp);

我的_document看起来像这样:


import Document from "next/document";
import { ServerStyleSheet } from "styled-components";

export default class MyDocument extends Document {
  static getInitialProps = async ctx => {
    const sheet = new ServerStyleSheet();
    const originalRenderPage = ctx.renderPage;

    try {
      ctx.renderPage = () =>
        originalRenderPage({
          enhanceApp: App => props => sheet.collectStyles(<App {...props} />)
        });

      const initialProps = await Document.getInitialProps(ctx);
      return {
        ...initialProps,
        styles: (
          <>
            {initialProps.styles}
            {sheet.getStyleElement()}
          </>
        )
      };
    } finally {
      sheet.seal();
    }
  };
}

2 个答案:

答案 0 :(得分:0)

在您的 async addExpense(req, res){ addOne(req, res, 'Expense') } async addPaymentMethod(req, res){ addOne(req, res, 'Payment method') } async function addOne(req, res, table) { if(!req.body.name){ return res.status(400).send({message: 'Expense cannot be added. Name is missing'}) } try{ switch (table) { case 'Expense': await addExpensesQuery(req) break; case 'Payment method': await addPaymentQuery(req) break; default: throw new Error('Unsupported operation') } return res.status(200).json({message: `${table} has been successfully added`}) }catch(err){ return res.status(400).send({message: err}) } } function addExpensesQuery (req) { const addExpense ='INSERT INTO budget.expenses_category_assigned_to_user VALUES(DEFAULT, $1, $2)' const queryValues = [ req.user.id, req.body.name ] return db.query(addExpense, queryValues) } function addPaymentQuery (req) { const addQuery = 'INSERT INTO budget.payment_methods_assigned_to_user VALUES (DEFAULT, $1, $2)' const queryValues = [ req.user.id, req.body.name ] return db.query(addQuery, queryValues) } 中,尝试在_document.js标签下面添加脚本

<NextScript />

答案 1 :(得分:0)

我一直在研究类似的问题。

我尝试了上面的答案,将 <script> 标记放在 <body> 中,但不幸的是,它还将 <script> 标记生成的内容呈现给 DOM(例如,它运行脚本正确,但还将其中的所有额外数据存储在 <body> 标记的底部)。

我还尝试将脚本包装在来自 <Head>next/head 组件中(仍在主体内部),这会阻止 DOM 呈现,但该修复根本没有运行脚本。

最后,对我的用例有用的是将脚本加载移动到 _app.js 文件中:它可以正确运行脚本,而不会向 DOM 呈现额外的内容。它看起来像这样:

import Head from "next/head";

function MyApp({ Component, pageProps }) {
  return (
    <React.Fragment>
      <Head>
        <script
          id="my-script"
          src="https://scriptsource.com/script"
          type="text/javascript"
        ></script>
      </Head>

      <LayoutComponent {...pageProps}>
        <Component {...pageProps} />
      </LayoutComponent>
    </React.Fragment>
  );
}

export default MyApp;

我不知道这个解决方案是否会导致任何我不知道的不良影响,但到目前为止它已经解决了我的问题。


更新(2021 年 6 月)

正如 Ahmed 在下面指出的,我上面写的解决方案有一些副作用。我注意到图像加载被脚本执行阻止。

我看到 Next 11 刚刚发布,其中包含用于此目的的新 <Script> 标签。

我把所有的props都移到了标签中,设置了strategy="beforeInteractive",然后直接把这个标签放到了Page组件中;现在一切都按预期运行。

以下是 Next 11 Script 标签的文档:https://nextjs.org/docs/basic-features/script