Next.js: document is not defined

后端 未结 6 1695
一个人的身影
一个人的身影 2021-02-07 15:22

I am trying to create a payment form where people can pay but I keep getting this error.

document is not defined

I\'m using Next.js. Ple

相关标签:
6条回答
  • 2021-02-07 15:46

    You have to make sure you have two things setup.

    1. DOM render is completed.
    2. Then load the function.

    Step 1: create hook isMounted this will make sure that your DOM is rendered.

    import React, {useEffect, useState} from 'react';
    
    function RenderCompleted() {
    
        const [mounted, setMounted] = useState(false);
    
        useEffect(() => {
            setMounted(true)
    
            return () => {
                setMounted(false)
            }
        });
    
        return mounted;
    }
    
    export default RenderCompleted;
    

    Inside function Payment load the hook :

    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
    
    

    Another way to do this is, to use head component of 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>
    
    0 讨论(0)
  • 2021-02-07 15:54

    This might be helpful to some else, I got this error when Material UI anchorEl is true

    const [anchoeEl, setAnchorEl] = useState(null)
    
    <Menu 
        anchorEl={anchorEl}  
        anchorOrigin={{
            vertical: "top"
            horizontal: "right"
        }}
    />
    
    0 讨论(0)
  • 2021-02-07 15:59

    You need to wrap your document using validator process.browser, because this document is belong to client side, and the error occured when nextjs render in server side.

    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 = () => {
    
            };
        }
    };
    
    0 讨论(0)
  • 2021-02-07 16:00

    To access the document in Next.js you need await the page render first then get it in a variable, like so:

    const [_document, set_document] = React.useState(null)
    
    React.useEffect(() => {
        set_document(document)
    }, [])
    
    0 讨论(0)
  • 2021-02-07 16:03

    I think, in server rendering mode, the document is undefined. You should be able to use it inside class lifecycle methods or 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
    
    0 讨论(0)
  • 2021-02-07 16:04

    You should read the difference between JS in node.js and JS in Browser. In node.js, you don't have DOM APIs (window, document, document.getElementById,...), the thing can be only have when your HTML is rendered in a thing called windows of Browsers. So next.js use node.js to run JS code and take result to render HTML file. But in node.js, nothing is windows of Browser.

    My English is quite bad. But I hope this answer will be helpful for you.

    0 讨论(0)
提交回复
热议问题