Next.js:文档未定义
Posted
技术标签:
【中文标题】Next.js:文档未定义【英文标题】:Next.js: document is not defined 【发布时间】:2022-01-06 23:35:09 【问题描述】:我正在尝试创建一个人们可以付款的付款表单,但我不断收到此错误。
文档未定义
我正在使用 Next.js。请参阅下面的代码:
import React from "react";
import Elements, StripeProvider from 'react-stripe-elements';
import CheckoutForm from '../../components/Payment/CheckoutForm';
import useRouter from 'next/router';
var stripe_load = () =>
var aScript = document.createElement('script');
aScript.type = 'text/javascript';
aScript.src = " https://js.stripe.com/v3/";
document.head.appendChild(aScript);
aScript.onload = () =>
;
;
function Payment(host)
const key = host.includes('localhost') ? 'test' : 't';
stripe_load();
const router = useRouter();
return (
<div className="Payment Main">
<StripeProvider apiKey=key>
<Elements>
<CheckoutForm planid=router.query.id/>
</Elements>
</StripeProvider>
<br/>
<br/>
<p>Powered by Stripe</p>
</div>
);
;
Payment.getInitialProps = async ctx =>
return host: ctx.req.headers.host
;
export default Payment
【问题讨论】:
相关:***.com/q/35068451/12860895 【参考方案1】:我认为,在服务器渲染模式下,文档是未定义的。 您应该能够在类生命周期方法或 useEffect 中使用它
import React, useEffect from "react";
import Elements, StripeProvider from 'react-stripe-elements';
import CheckoutForm from '../../components/Payment/CheckoutForm';
import useRouter from 'next/router';
var stripe_load = () =>
var aScript = document.createElement('script');
aScript.type = 'text/javascript';
aScript.src = " https://js.stripe.com/v3/";
document.head.appendChild(aScript);
aScript.onload = () =>
;
;
function Payment(host)
const key = host.includes('localhost') ? 'test' : 't';
useEffect(() =>
var aScript = document.createElement('script');
aScript.type = 'text/javascript';
aScript.src = " https://js.stripe.com/v3/";
document.head.appendChild(aScript);
aScript.onload = () =>
;
, [])
//stripe_load();
const router = useRouter();
return (
<div className="Payment Main">
<StripeProvider apiKey=key>
<Elements>
<CheckoutForm planid=router.query.id/>
</Elements>
</StripeProvider>
<br/>
<br/>
<p>Powered by Stripe</p>
</div>
);
;
Payment.getInitialProps = async ctx =>
return host: ctx.req.headers.host
;
export default Payment
【讨论】:
【参考方案2】:您需要使用验证器process.browser
包装您的document
,因为该文档属于客户端,并且nextjs 在服务器端渲染时发生错误。
var stripe_load = () =>
if (process.browser)
var aScript = document.createElement('script');
aScript.type = 'text/javascript';
aScript.src = " https://js.stripe.com/v3/";
document.head.appendChild(aScript);
aScript.onload = () =>
;
;
【讨论】:
请注意,process.browser
已被弃用。您现在应该使用typeof window === 'undefined'
。参考github.com/zeit/next.js/issues/5354#issuecomment-520305040【参考方案3】:
对我来说,这个错误是由很多错误引起的: 首先,你必须使用
if (typeof window !== "undefined")
对于每个 window.
和 document.
,尤其是对于 localStorage.
函数(我自己忘记将这个 if 子句用于 localStorage.getItem 并且错误没有修复)
另一个问题是下面这行的导入完全错误!:
import router from "next/client";
【讨论】:
【参考方案4】:要访问 Next.js 中的文档,您需要先等待页面渲染,然后将其放入变量中,如下所示:
const [_document, set_document] = React.useState(null)
React.useEffect(() =>
set_document(document)
, [])
【讨论】:
正是我需要的。非常感谢!【参考方案5】:你应该阅读 node.js 中的 JS 和 Browser 中的 JS 之间的区别。在 node.js 中,您没有 DOM API(window、document、document.getElementById、...),只有当您的 html 在称为浏览器窗口的东西中呈现时才能拥有。所以 next.js 使用 node.js 来运行 JS 代码并获取结果来渲染 HTML 文件。但是在node.js中,什么都不是Browser的窗口。
我的英语很差。但我希望这个答案对你有所帮助。
【讨论】:
【参考方案6】:例如,当模块包含仅在浏览器中工作的库时。有时动态导入可以解决这个问题。
看看下面的例子:
import dynamic from 'next/dynamic'
const DynamicComponentWithNos-s-r = dynamic(
() => import('../components/hello3'),
s-s-r: false
)
function Home()
return (
<div>
<Header />
<DynamicComponentWithNos-s-r />
<p>HOME PAGE is here!</p>
</div>
)
export default Home
【讨论】:
非常被低估的答案。接受我的投票并感谢您的帮助!【参考方案7】:您必须确保设置了两件事。
-
DOM 渲染完成。
然后加载函数。
第 1 步:创建钩子 isMounted 这将确保您的 DOM 被渲染。
import React, useEffect, useState from 'react';
function RenderCompleted()
const [mounted, setMounted] = useState(false);
useEffect(() =>
setMounted(true)
return () =>
setMounted(false)
);
return mounted;
export default RenderCompleted;
内部函数支付加载钩子:
import React, useEffect from "react";
import Elements, StripeProvider from 'react-stripe-elements';
import CheckoutForm from '../../components/Payment/CheckoutForm';
import useRouter from 'next/router';
import RenderCompleted from '../hooks/isMounted';
var stripe_load = () =>
var aScript = document.createElement('script');
aScript.type = 'text/javascript';
aScript.src = " https://js.stripe.com/v3/";
document.head.appendChild(aScript);
aScript.onload = () =>
;
;
function Payment(host)
const[key,setKey] = useEffect('');
//will help you on re-render or host changes
useEffect(()=>
const key = host.includes('localhost') ? 'test' : 't';
setKey(key);
,[host])
useEffect(() =>
var aScript = document.createElement('script');
aScript.type = 'text/javascript';
aScript.src = " https://js.stripe.com/v3/";
document.head.appendChild(aScript);
aScript.onload = () =>
;
, [isMounted])
const router = useRouter();
const isMounted = RenderCompleted();
return (
<div className="Payment Main">
<StripeProvider apiKey=key>
<Elements>
<CheckoutForm planid=router.query.id/>
</Elements>
</StripeProvider>
<br/>
<br/>
<p>Powered by Stripe</p>
</div>
);
;
Payment.getInitialProps = async ctx =>
return host: ctx.req.headers.host
;
export default Payment
另一种方法是使用 next.js 的头部组件:https://nextjs.org/docs/api-reference/next/head
<Head>
<title>My page title</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
</Head>
【讨论】:
【参考方案8】:您可以在关闭 s-s-r 的情况下使用名为 dynamic imports 的新功能。这是重新渲染组件的一种解决方法。
【讨论】:
【参考方案9】:这可能对其他人有帮助,当 Material UI anchorEl 为 true 时出现此错误
const [anchoeEl, setAnchorEl] = useState(null)
<Menu
anchorEl=anchorEl
anchorOrigin=
vertical: "top"
horizontal: "right"
/>
【讨论】:
以上是关于Next.js:文档未定义的主要内容,如果未能解决你的问题,请参考以下文章
Next JS - ReferenceError:文档未定义[重复]
Next.js 上下文提供程序用页面特定布局组件包装 App 组件,提供未定义的数据
next.js 环境变量未定义(Next.js 10.0.5)