Estoy tratando de incorporar la función de inicio de sesión de Google en mi aplicación Next. Así es como lo he estado haciendo.
En _document.js
import React from 'react'; import Document, {Html, Head, Main, NextScript } from 'next/document'; export default class MyDocument extends Document{ render(){ return( <Html lang="en"> <Head> <meta name="theme-color" /> {/* This should add `google` to `window` */} <script type="application/javascript" src="https://accounts.google.com/gsi/client" async /> </Head> <body> <Main /> <NextScript /> </body> </Html> ); } } Y luego en pages/login.js
import { React, useEffect, ... } from 'react' export default function LoginPage (props) { // When page is rendered, render the 'Sign-in with Google' button useEffect(() => { window.google.accounts.id.initialize({ client_id: process.env.NEXT_PUBLIC_GOOGLE_CLIENT_ID, callback: res => { console.log(res) } }) window.google.accounts.id.renderButton( document.getElementById('googleSignIn'), { theme: 'filled_blue', size: 'large', text: 'continue_with' } ) }, []) return (<> {/* Provide an element for the button to render into */} <div id="googleSignIn" /> </>) }Pero esto arroja un error:
login.js:48 Uncaught TypeError: Cannot read properties of undefined (reading 'accounts')
En otras palabras, window.google no está definido.
¿Qué tiene de malo esto?
NextJS siempre procesa previamente las páginas en el servidor, en este caso window no está disponible. Siempre puede usar la biblioteca next/router . esperar hasta que la página cargue en el cliente
import { React, useEffect, ... } from 'react' import { useRouter } from 'next/router' export default function LoginPage (props) { // When page is rendered, render the 'Sign-in with Google' button const router=useRouter() //create router state useEffect(() => { if(window){ //check window if exist on each effect execution window.google.accounts.id.initialize({ client_id: process.env.NEXT_PUBLIC_GOOGLE_CLIENT_ID, callback: res => { console.log(res) } }) window.google.accounts.id.renderButton( document.getElementById('googleSignIn'), { theme: 'filled_blue', size: 'large', text: 'continue_with' } ) } }, [router]) // to run again when client router loads return (<> {/* Provide an element for the button to render into */} <div id="googleSignIn" /> </>) }