隆Estamos en directo en Twitch!

隆Entra y participa!

Imagen de la etiqueta javascript

C贸mo solucionar el error ReferenceError: window is not defined

4 minutos de lectura驴Una errata? Edita el art铆culo

En alg煤n momento te vas a encontrar el error ReferenceError: window is not defined si desarrollas con JavaScript. Esto es porque est谩s dando por hecho que todos los entornos donde se ejecuta este lenguaje tiene acceso a este objeto global… 隆y no es as铆!

Por ejemplo, si est谩s trabajando con Node.js, no tienes acceso al objeto window y, por lo tanto, es posible que si intentas acceder a window te devuelva este error:

const value = window.localStorage.getItem('key')

En Node.js el localStorage no est谩 disponible. En otros entornos de ejecuci贸n como Deno s铆 que lo est谩, pero es algo particular ya que han adaptado la API para que funcione en la parte del servidor.

Igual ni siquiera est谩s usando conscientemente Node.js pero hay frameworks como Remix, Nuxt o Next.js que parte de su c贸digo se ejecutan en la parte del servidor y, all铆, no tienen acceso al objeto window.

C贸mo solucionar el problema si es en tu c贸digo

Si el problema est谩 en tu c贸digo es bastante sencillo. Encuentra d贸nde est茅s accediendo a una propiedad del objeto window y elimina el c贸digo. Si eso no es posible (por ejemplo, un c贸digo que se ejecuta tanto en servidor como en cliente) entonces puedes envolver el c贸digo en un condicional que compruebe si tiene acceso a window.

let value
if (typeof window !== 'undefined') {
  value = window.localStorage.getItem('key')
}

驴Por qu茅 usar typeof window !== 'undefined' en lugar de window === undefined? Es bien sencillo. El primero no fallar谩 al hacer la comprobaci贸n pero el segundo fallar铆a ya que window no es accesible y no puede mirar que tenga el valor undefined.

En JavaScript hay que diferenciar entre el valor undefined y que una variable no est谩 definida, por lo tanto no es accesible, y su tipo sea undefined.

C贸mo solucionar el problema si es de una librer铆a

Tambi茅n es posible que encuentres este problema con algunas librer铆as de terceros que, al importarlas, est谩n pensadas para ser ejecutadas s贸lo en el cliente. No es un problema com煤n (ya que normalmente revisan si tienen acceso al objeto antes de intentar referirse a 茅l) pero puede pasar.

// C贸digo ejecutado en el servidor
import useSomething from 'dependencia-externa'

useSomething()
// ReferenceError: window is not defined

En estos casos lo mejor es revisar toda la traza para determinar el origen del problema…

Una vez detectes la dependencia culpable, tendr谩s diferentes opciones:

  • Buscar una alternativa que no tenga el problema.
  • Revisar si realmente necesitas cargar la dependencia en ese punto y si puedes mover la importaci贸n y uso de la dependencia en un archivo que s贸lo se ejecute en el cliente.
  • Cargar de forma din谩mica la dependencia s贸lo cuando sepas que est谩s en el cliente.
if (typeof window !== 'undefined') {
  import('dependencia-externa')
    .then(({default: useSomething}) => useSomething())
}

T铆pica mala pr谩ctica en React 鈿涳笍…

Existe una mala pr谩ctica en React que puede traer graves problemas de rendimiento en tus aplicaciones. En ocasiones, en el cuerpo de la funci贸n de tu componente, te puedes encontrar el error de referencia al intentar acceder a window:

export default User () {
  const user = window.localStorage.getItem('user')
  return <h1>{user}</h1>
}

Al ver algo as铆 puedes caer en la tentaci贸n de hacer la soluci贸n que hemos comentado anteriormente…

// 鉂 este c贸digo ser铆a INCORRECTO en el servidor
// y s贸lo est谩 como ejemplo para ilustrar
export default User () {
  let user = ''
  if (typeof window !== 'undefined') {
    user = window.localStorage.getItem('user')
  }
  return <h1>{user}</h1>
}

驴Cu谩l es el problema de este c贸digo? Pues que servidor y cliente renderizar铆an elementos diferentes. Esto crear铆a una discordancia y en cliente se ver铆a forzado a re-renderizar esa parte del 谩rbol, lo que puede ser muy costoso.

Para evitar esto, lo ideal es que pases esta comprobaci贸n a un useEffect ya que s贸lo se ejecutan en el cliente y cada vez que se renderiza el componente. En este caso, con las dependencias vac铆as, hacemos que s贸lo se ejecute en el primer renderizado:

// 鉁 Esta ser铆a la forma correcta de lidiar
// con estos problemas en servidor/cliente
import { useEffect } from 'react'

export default User () {
  const [user, setUser] = useState('')

  useEffect(() => {
    // esto s贸lo se ejecuta en cliente
    const user = window.localStorage.getItem('user')
    setUser(user)
  }, []) // dejamos las dependencias vac铆as para que s贸lo se ejecute la primera vez

  return <h1>{user}</h1>
}

Si tu aplicaci贸n es s贸lo Client Side Rendering entonces no te tienes que preocupar de estas cosas… aunque hoy en d铆a es cada vez m谩s complicado que sea as铆, ya que estar铆as perdiendo algunas ventajas de SEO y rendimiento.

Conclusiones

Cuando encuentres el error de ReferenceError: window is not defined es porque est谩s intentando acceder al objeto window desde el servidor (normalmente Node.js) y no est谩 accesible. Revisa tu c贸digo o las dependencias que est谩s usando y evita acceder al objeto desde el servidor.

Contenido del art铆culo

Comparte el art铆culo