Next.js: 文档未定义
Next.js: document is not defined
我正在尝试创建一个人们可以付款的付款表单,但我一直收到此错误。
document is not defined
我正在使用 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
我认为,在服务器渲染模式下,文档是未定义的。
您应该能够在 class 生命周期方法或 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
您需要使用验证器 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 = () => {
};
}
};
您必须确保设置了两件事。
- 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>
您应该阅读 node.js 中的 JS 和浏览器中的 JS 之间的区别。在 node.js 中,您没有 DOM API(window、文档、document.getElementById、...),只有当您的 HTML 呈现在浏览器的一个叫做 windows 的东西中。所以 next.js 使用 node.js 到 运行 JS 代码并将结果呈现给 HTML 文件。但是在node.js中,浏览器的windows什么都没有。
我的英文很烂。不过希望这个回答对你有所帮助。
要访问 Next.js 中的文档,您需要先等待页面呈现,然后将其放入变量中,如下所示:
const [_document, set_document] = React.useState(null)
React.useEffect(() => {
set_document(document)
}, [])
这可能对其他人有帮助,当 Material UI anchorEl 为真时我得到了这个错误
const [anchoeEl, setAnchorEl] = useState(null)
<Menu
anchorEl={anchorEl}
anchorOrigin={{
vertical: "top"
horizontal: "right"
}}
/>
对我来说,这个错误是由很多错误引起的:
首先,你必须使用
if (typeof window !== "undefined") {
对于每个 window.
和 document.
,尤其是对于 localStorage.
函数(我自己忘记为 localStorage.getItem 使用这个 if 子句并且错误没有修复)
另一个问题是下面一行的导入完全错误!:
import {router} from "next/client";
例如,当模块包含一个只能在浏览器中运行的库时。有时动态导入可以解决这个问题。
看看下面的例子:
import dynamic from 'next/dynamic'
const DynamicComponentWithNoSSR = dynamic(
() => import('../components/hello3'),
{ ssr: false }
)
function Home() {
return (
<div>
<Header />
<DynamicComponentWithNoSSR />
<p>HOME PAGE is here!</p>
</div>
)
}
export default Home
您可以在关闭 ssr 的情况下使用名为 dynamic imports 的新功能。这是重新渲染组件的解决方法。
我正在尝试创建一个人们可以付款的付款表单,但我一直收到此错误。
document is not defined
我正在使用 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
我认为,在服务器渲染模式下,文档是未定义的。 您应该能够在 class 生命周期方法或 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
您需要使用验证器 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 = () => {
};
}
};
您必须确保设置了两件事。
- 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>
您应该阅读 node.js 中的 JS 和浏览器中的 JS 之间的区别。在 node.js 中,您没有 DOM API(window、文档、document.getElementById、...),只有当您的 HTML 呈现在浏览器的一个叫做 windows 的东西中。所以 next.js 使用 node.js 到 运行 JS 代码并将结果呈现给 HTML 文件。但是在node.js中,浏览器的windows什么都没有。
我的英文很烂。不过希望这个回答对你有所帮助。
要访问 Next.js 中的文档,您需要先等待页面呈现,然后将其放入变量中,如下所示:
const [_document, set_document] = React.useState(null)
React.useEffect(() => {
set_document(document)
}, [])
这可能对其他人有帮助,当 Material UI anchorEl 为真时我得到了这个错误
const [anchoeEl, setAnchorEl] = useState(null)
<Menu
anchorEl={anchorEl}
anchorOrigin={{
vertical: "top"
horizontal: "right"
}}
/>
对我来说,这个错误是由很多错误引起的: 首先,你必须使用
if (typeof window !== "undefined") {
对于每个 window.
和 document.
,尤其是对于 localStorage.
函数(我自己忘记为 localStorage.getItem 使用这个 if 子句并且错误没有修复)
另一个问题是下面一行的导入完全错误!:
import {router} from "next/client";
例如,当模块包含一个只能在浏览器中运行的库时。有时动态导入可以解决这个问题。
看看下面的例子:
import dynamic from 'next/dynamic'
const DynamicComponentWithNoSSR = dynamic(
() => import('../components/hello3'),
{ ssr: false }
)
function Home() {
return (
<div>
<Header />
<DynamicComponentWithNoSSR />
<p>HOME PAGE is here!</p>
</div>
)
}
export default Home
您可以在关闭 ssr 的情况下使用名为 dynamic imports 的新功能。这是重新渲染组件的解决方法。