Tengo una ruta de devolución de llamada en mi aplicación que recibe el token de acceso del proceso de autenticación en el fragmento hash de URL. Me gustaría analizarlo y guardarlo en la tienda redux. Solía obtenerlo a través de window.location.hash
antes de cambiar a la siguiente, pero esto no está disponible cuando la página se procesa en el lado del servidor (también el fragmento de hash aparentemente no se envía al servidor, por lo que no puedo analizarlo allí ).
¿Hay alguna forma de restringir algún código para que se ejecute solo en el lado del cliente? ¿O hay alguna otra forma de lograrlo?
@vanniewelt : el componente Async importado dinámicamente se carga en el cliente y puede colocar toda la lógica del lado del cliente allí.
Además, el ciclo de vida de ComponentWillReceiveProps recibirá solicitudes en accesorios mientras esté en el lado del servidor.
Puede comprobar si esta variable existe e inyectar su código de cliente.
Si la biblioteca necesita una variable de ventana, le sugiero que use importaciones dinámicas, funciona bien para mí.
https://github.com/zeit/next.js/tree/v3-beta/examples/with-dynamic-import
También puede usar el método de ciclo componentDidMount
vida
@vanniewelt Siempre puedes mirar process.browser
..
if (process.browser) {
// client-side-only code
}
editar por @Timer :
@vanniewelt Siempre puedes mirar typeof window
..
if (typeof window !== 'undefined') {
// client-side-only code
}
sí, pero no es el mejor enfoque.
digamos que quiero verificar si el usuario está autenticado, y quiero ejecutar esa verificación solo en el lado del cliente por varias razones, una de ellas es porque estoy almacenando JWT en localStorage y no quiero almacenarlo en una cookie.
Entonces, en este caso, en la primera página cargue con:
if (process.browser) {
// client-side-only code
}
el código dentro del alcance no se ejecutará en absoluto, ni en el servidor ni en el cliente, se ejecutará solo si el cambio de ruta se activó desde el cliente
@sarkistlt Puede tener razón en algunos casos dependiendo de dónde se coloque ese código ... pero ...
Si ese código se ejecuta en el servidor, la ejecución no llegará a // client-side-only code
. Si ese código se ejecuta en el cliente, la ejecución llegará a // client-side-only code
.
Parece una respuesta válida a la pregunta:
¿Hay alguna forma de restringir algún código para que se ejecute solo en el lado del cliente?
@sarkistlt componentDidMount
solo se ejecuta en el lado del cliente, componentWillMount
se ejecuta tanto en el lado del cliente como en el del servidor.
@sarkistlt https://reactjs.org/docs/react-component.html#componentwillmount
Este es el único enlace del ciclo de vida llamado en la representación del servidor.
Lo hice muchas veces, estás confundiendo componentWillMount
con componentDidMount
.
@sergiodxa en realidad tienes razón, acabo de ejecutar la prueba. ¡Gracias!
El enlace componentWillMount
@sergiodxa componentWillMount
se cambió a https://reactjs.org/docs/react-component.html#unsafe_componentwillmount.
Necesitaba el módulo mapbox-gl
que es una biblioteca del lado del cliente dentro de ComponentDidMount
y me deshice de un error feo ReferenceError: self is not defined
No pude hacer Mapbox usando componentDidMount
porque el componente aún intenta ser procesado (no sé qué está tratando de hacer exactamente) en el servidor (terminé teniendo el mismo problema que @elaich ).
El uso de Dynamic Imports como lo sugirió @ aga5tya hizo el truco 🎉.
@vanniewelt : el componente Async importado dinámicamente se carga en el cliente y puede colocar toda la lógica del lado del cliente allí.
Además, el ciclo de vida de ComponentWillReceiveProps recibirá solicitudes en accesorios mientras esté en el lado del servidor.
Puede comprobar si esta variable existe e inyectar su código de cliente.Si la biblioteca necesita una variable de ventana, le sugiero que use importaciones dinámicas, funciona bien para mí.
https://github.com/zeit/next.js/tree/v3-beta/examples/with-dynamic-import
Para aquellos que se han topado con este hilo en busca de la solución. El enlace de Importaciones dinámicas mencionado anteriormente está roto. Se ha actualizado y se puede encontrar en Dynamic Imports .
Si tiene un componente que siempre se supone que debe ejecutarse en el cliente y no desea usar Importaciones dinámicas (por ejemplo: las personas pueden olvidar que necesitan usarlas), puede usar Hooks (o el equivalente componentDidMount
) de la siguiente manera:
import React, { useEffect, useState } from 'react'
function CreateInteraction ({ input }) {
const [isComponentMounted, setIsComponentMounted] = useState(false)
useEffect(() => setIsComponentMounted(true), [])
if(!isComponentMounted) {
return null
}
return <h1>I'm only executed on the client!</h1>
}
Solo para agregar a algunas respuestas que ya son buenas: mi proyecto actual hace una gran cantidad de renderizado condicional en ambas direcciones, así que uso un componente para esto:
import React, { useEffect, useState } from "react";
export interface ConditionallyRenderProps {
client?: boolean;
server?: boolean;
}
const ConditionallyRender: React.FC<ConditionallyRenderProps> = (props) => {
const [isMounted, setIsMounted] = useState(false);
useEffect(() => setIsMounted(true), []);
if(!isMounted && props.client) {
return null;
}
if(isMounted && props.server) {
return null;
}
return props.children as React.ReactElement;
};
export default ConditionallyRender;
Y luego úselo de la siguiente manera:
<Layout>
<ConditionallyRender server>
<p>This is rendered only on server.</p>
</ConditionallyRender>
<ConditionallyRender client>
<p>This is rendered only on client.</p>
</ConditionallyRender>
</Layout>
Si está utilizando cualquier biblioteca que acceda a la API del navegador, puede importar módulos dinámicamente con SSR = false como segundo argumento.
const DynamicComponentWithNoSSR = dynamic(
() => import('../components/hello3'),
{ ssr: false }
)
https://nextjs.org/docs/advanced-features/dynamic-import
Si está utilizando cualquier biblioteca que acceda a la API del navegador, puede importar módulos dinámicamente con SSR = false como segundo argumento.
const DynamicComponentWithNoSSR = dynamic( () => import('../components/hello3'), { ssr: false } )
https://nextjs.org/docs/advanced-features/dynamic-import
¡También necesitará agregar esta importación si desea utilizar la importación "dinámica" para cualquiera que esté mirando el código @ yashwant-dangi!
import dynamic from 'next/dynamic'
@Timer Noté que https://github.com/vercel/next.js/issues/2473#issuecomment -362119102, que volví a editar para reflejar el comentario original y tu edición.
typeof window !== 'undefined'
lugar de solo process.browser
? Es más detallado, así que si no hay ninguna razón aquí, prefiero usar process.browser
.¿Por qué deberíamos usar typeof window! == 'undefined' en lugar de solo process.browser? Es más detallado, así que si no hay ninguna razón aquí, prefiero usar process.browser.
process.browser
no es estándar y solo está disponible en el entorno del paquete web, lo que significa que es probable que se rompa en el futuro, por ejemplo, el paquete web 5 ya no es polyfills process
.
Una alternativa a typeof window !== "undefined"
podría ser Object.prototype.isPrototypeOf(window)
. Sin embargo, según esta publicación , los paquetes producidos por Next.js detectan lo anterior y cualquier cosa que produzca paquetes más ligeros debe considerarse una victoria.
Comentario más útil
@vanniewelt Siempre puedes mirar
process.browser
..editar por @Timer :
@vanniewelt Siempre puedes mirar
typeof window
..