Next.js: P: Cómo ejecutar código solo en el lado del cliente

Creado en 5 jul. 2017  ·  19Comentarios  ·  Fuente: vercel/next.js

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?

Comentario más útil

@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
}

Todos 19 comentarios

@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.

  1. ¿Por qué deberíamos usar 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 .
  2. La próxima vez que edite un comentario de un colaborador, ¿podría hacer que la edición sea aparente en su comentario? En primer lugar, puede hacer que el hilo sea confuso, como lo hizo aquí, donde el siguiente comentario es una respuesta a mi comentario específico. En segundo lugar, es engañoso ya que eso no es lo que escribí, y tampoco eso es lo que la gente lee cuando reacciona.

¿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.

¿Fue útil esta página
0 / 5 - 0 calificaciones