Obtenga la altura de ventana / ventana en ReactJS

160

¿Cómo obtengo la altura de la ventana gráfica en ReactJS? En JavaScript normal uso

window.innerHeight()

pero usando ReactJS, no estoy seguro de cómo obtener esta información. Mi entendimiento es que

ReactDOM.findDomNode()

solo funciona para componentes creados. Sin embargo, este no es el caso para el elemento documento body, lo que podría darme altura de la ventana.

Jabran Saeed
fuente

Respuestas:

245

Esta respuesta es similar a la de Jabran Saeed, excepto que también maneja el cambio de tamaño de la ventana. Lo tengo de aquí .

constructor(props) {
  super(props);
  this.state = { width: 0, height: 0 };
  this.updateWindowDimensions = this.updateWindowDimensions.bind(this);
}

componentDidMount() {
  this.updateWindowDimensions();
  window.addEventListener('resize', this.updateWindowDimensions);
}

componentWillUnmount() {
  window.removeEventListener('resize', this.updateWindowDimensions);
}

updateWindowDimensions() {
  this.setState({ width: window.innerWidth, height: window.innerHeight });
}
carpa moteada
fuente
3
Puede eliminar .bind(this)de los argumentos de devolución de llamada ya que está vinculado por el constructor.
Scymex
1
Nitpick: el código en el constructor probablemente debería ser this.state = { width: 0, height: 0 };para que los vars de estado no cambien sus tipos (si entiendo correctamente window.innerWidth es entero ). No cambia nada, excepto que hace que el código sea más fácil de entender en mi humilde opinión. ¡Gracias por la respuesta!
johndodo
1
@johndodo. Whoops Editado
speckledcarp
77
¿Por qué no this.state = { width: window.innerWidth, height: window.innerHeight };comenzar?
Gerbus
1
Quizás no sea la mejor idea, usar una devolución de llamada para apuntar al evento de cambio de tamaño de la ventana y luego reorientar el objeto de la ventana global dentro de la devolución de llamada. Por razones de rendimiento, legibilidad y convenciones, voy a actualizarlo para usar los valores de evento dados.
GoreDefex
176

Usando ganchos (React 16.8.0+)

Crea un useWindowDimensionsgancho.

import { useState, useEffect } from 'react';

function getWindowDimensions() {
  const { innerWidth: width, innerHeight: height } = window;
  return {
    width,
    height
  };
}

export default function useWindowDimensions() {
  const [windowDimensions, setWindowDimensions] = useState(getWindowDimensions());

  useEffect(() => {
    function handleResize() {
      setWindowDimensions(getWindowDimensions());
    }

    window.addEventListener('resize', handleResize);
    return () => window.removeEventListener('resize', handleResize);
  }, []);

  return windowDimensions;
}

Y después de eso podrás usarlo en tus componentes de esta manera

const Component = () => {
  const { height, width } = useWindowDimensions();

  return (
    <div>
      width: {width} ~ height: {height}
    </div>
  );
}

Ejemplo de trabajo

Respuesta original

Es lo mismo en React, puede usar window.innerHeightpara obtener la altura de la ventana gráfica actual.

Como puedes ver aqui

QoP
fuente
2
window.innerHeight no es una función, es una propiedad
Jairo
2
Parece que Kevin Danikowski editó la respuesta y de alguna manera se aprobó ese cambio. Ya está arreglado.
QoP
3
@FeCH elimina el detector de eventos cuando el componente se desmonta. Se llama la cleanupfunción, puedes leer sobre esto aquí
QoP
1
¿Alguna idea para obtener el mismo enfoque con SSR (NextJS)?
roadev
1
@roadev en NextJS, también puede verificar si el reqaccesorio está disponible en getInitialProps. Si es así, se está ejecutando en el servidor, entonces no tendrá variables de ventana.
giovannipds
54
class AppComponent extends React.Component {

  constructor(props) {
    super(props);
    this.state = {height: props.height};
  }

  componentWillMount(){
    this.setState({height: window.innerHeight + 'px'});
  }

  render() {
    // render your component...
  }
}

Establecer los accesorios

AppComponent.propTypes = {
 height:React.PropTypes.string
};

AppComponent.defaultProps = {
 height:'500px'
};

la altura de la ventana gráfica ahora está disponible como {this.state.height} en la plantilla de representación

Jabran Saeed
fuente
13
Esta solución no se actualiza si se cambia el tamaño de la ventana del navegador
speckledcarp
1
Para su información, la actualización del estado después del montaje de un componente desencadenará una segunda llamada render () y puede conducir a la propiedad / diseño de la agitación. github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/…
Haukur Kristinsson
1
@HaukurKristinsson, ¿cómo superar esto?
Richard
1
@JabranSaeed ¿por qué no seguir adelante y establecer la altura en el constructor en lugar de actualizarlo en el soporte? Si es necesario tomar en consideración los apoyos se puede predeterminado El valor de esta manera: height: window.innerHeight || props.height. Esto no solo simplificará el código sino que también eliminará los cambios de estado innecesarios.
JohnnyQ
componentWillMountya no se recomienda, consulte reactjs.org/docs/react-component.html#unsafe_componentwillmount
holmberd
26

Acabo de editar la respuesta actual de QoP para admitir SSR y usarla con Next.js (React 16.8.0+):

/hooks/useWindowDimensions.js :

import { useState, useEffect } from 'react';

export default function useWindowDimensions() {

  const hasWindow = typeof window !== 'undefined';

  function getWindowDimensions() {
    const width = hasWindow ? window.innerWidth : null;
    const height = hasWindow ? window.innerHeight : null;
    return {
      width,
      height,
    };
  }

  const [windowDimensions, setWindowDimensions] = useState(getWindowDimensions());

  useEffect(() => {
    if (hasWindow) {
      function handleResize() {
        setWindowDimensions(getWindowDimensions());
      }

      window.addEventListener('resize', handleResize);
      return () => window.removeEventListener('resize', handleResize);
    }
  }, [hasWindow]);

  return windowDimensions;
}

/yourComponent.js :

import useWindowDimensions from './hooks/useWindowDimensions';

const Component = () => {
  const { height, width } = useWindowDimensions();
  /* you can also use default values or alias to use only one prop: */
  // const { height: windowHeight = 480 } useWindowDimensions();

  return (
    <div>
      width: {width} ~ height: {height}
    </div>
  );
}
giovannipds
fuente
Gran solución
Jeremy E
Intenté hacer esto con NextJS pero parece que solo tiene el tamaño correcto después de cambiar el tamaño de la pantalla. Supongo que se debe a la representación del lado del servidor nextJS. ¿Tienes alguna idea?
herohamp hace
15

La respuesta de @speckledcarp es excelente, pero puede ser tediosa si necesita esta lógica en varios componentes. Puede refactorizarlo como un HOC (componente de orden superior) para que esta lógica sea más fácil de reutilizar.

withWindowDimensions.jsx

import React, { Component } from "react";

export default function withWindowDimensions(WrappedComponent) {
    return class extends Component {
        state = { width: 0, height: 0 };

        componentDidMount() {
            this.updateWindowDimensions();
            window.addEventListener("resize", this.updateWindowDimensions);
        }

        componentWillUnmount() {
            window.removeEventListener("resize", this.updateWindowDimensions);
        }

        updateWindowDimensions = () => {
            this.setState({ width: window.innerWidth, height: window.innerHeight });
        };

        render() {
            return (
                <WrappedComponent
                    {...this.props}
                    windowWidth={this.state.width}
                    windowHeight={this.state.height}
                    isMobileSized={this.state.width < 700}
                />
            );
        }
    };
}

Luego en su componente principal:

import withWindowDimensions from './withWindowDimensions.jsx';

class MyComponent extends Component {
  render(){
    if(this.props.isMobileSized) return <p>It's short</p>;
    else return <p>It's not short</p>;
}

export default withWindowDimensions(MyComponent);

También puede "apilar" HOC si tiene otro que necesita usar, p. Ej. withRouter(withWindowDimensions(MyComponent))

Editar: Iría con un gancho React hoy en día ( ejemplo anterior aquí ), ya que resuelven algunos de los problemas avanzados con HOC y clases

James L.
fuente
1
Buen trabajo @ James
Manish
8

Acabo de pasar un tiempo serio resolviendo algunas cosas con React y desplazando eventos / posiciones, así que para aquellos que todavía están buscando, esto es lo que encontré:

La altura de la vista se puede encontrar usando window.innerHeight o mediante document.documentElement.clientHeight. (Altura de la ventana gráfica actual)

La altura de todo el documento (cuerpo) se puede encontrar usando window.document.body.offsetHeight.

Si está intentando encontrar la altura del documento y saber cuándo ha tocado fondo, esto es lo que se me ocurrió:

if (window.pageYOffset >= this.myRefII.current.clientHeight && Math.round((document.documentElement.scrollTop + window.innerHeight)) < document.documentElement.scrollHeight - 72) {
        this.setState({
            trueOrNot: true
        });
      } else {
        this.setState({
            trueOrNot: false
        });
      }
    }

(Mi barra de navegación tenía 72 píxeles en posición fija, por lo tanto, el -72 para obtener un mejor desencadenador de evento de desplazamiento)

Por último, aquí hay una serie de comandos de desplazamiento a console.log (), que me ayudaron a descubrir mis matemáticas activamente.

console.log('window inner height: ', window.innerHeight);

console.log('document Element client hieght: ', document.documentElement.clientHeight);

console.log('document Element scroll hieght: ', document.documentElement.scrollHeight);

console.log('document Element offset height: ', document.documentElement.offsetHeight);

console.log('document element scrolltop: ', document.documentElement.scrollTop);

console.log('window page Y Offset: ', window.pageYOffset);

console.log('window document body offsetheight: ', window.document.body.offsetHeight);

¡Uf! Espero que ayude a alguien!

thielr7
fuente
3
// just use (useEffect). every change will be logged with current value
import React, { useEffect } from "react";

export function () {
  useEffect(() => {
    window.addEventListener('resize', () => {
      const myWidth  = window.innerWidth;
      console.log('my width :::', myWidth)
   })
  },[window])

  return (
    <>
      enter code here
   </>
  )
}
Joabe
fuente
1
Bienvenido a Stack Overflow. Los volcados de código sin ninguna explicación rara vez son útiles. Stack Overflow se trata de aprender, no de proporcionar fragmentos para copiar y pegar a ciegas. Por favor, editar su pregunta y explicar cómo funciona mejor que lo que el PO siempre.
Chris
2

Las respuestas de @speckledcarp y @Jamesl son brillantes. En mi caso, sin embargo, necesitaba un componente cuya altura pudiera extender la altura de la ventana completa, condicional en el momento de renderizado ... pero llamar a un HOC dentro render()vuelve a representar todo el subárbol. BAAAD.

Además, no estaba interesado en obtener los valores como accesorios, sino que simplemente quería un padre divque ocupara toda la altura de la pantalla (o ancho, o ambos).

Entonces escribí un componente principal que proporciona un div de altura completa (y / o ancho). Auge.

Un caso de uso:

class MyPage extends React.Component {
  render() {
    const { data, ...rest } = this.props

    return data ? (
      // My app uses templates which misbehave badly if you manually mess around with the container height, so leave the height alone here.
      <div>Yay! render a page with some data. </div>
    ) : (
      <FullArea vertical>
        // You're now in a full height div, so containers will vertically justify properly
        <GridContainer justify="center" alignItems="center" style={{ height: "inherit" }}>
          <GridItem xs={12} sm={6}>
            Page loading!
          </GridItem>
        </GridContainer>
      </FullArea>
    )

Aquí está el componente:

import React, { Component } from 'react'
import PropTypes from 'prop-types'

class FullArea extends Component {
  constructor(props) {
    super(props)
    this.state = {
      width: 0,
      height: 0,
    }
    this.getStyles = this.getStyles.bind(this)
    this.updateWindowDimensions = this.updateWindowDimensions.bind(this)
  }

  componentDidMount() {
    this.updateWindowDimensions()
    window.addEventListener('resize', this.updateWindowDimensions)
  }

  componentWillUnmount() {
    window.removeEventListener('resize', this.updateWindowDimensions)
  }

  getStyles(vertical, horizontal) {
    const styles = {}
    if (vertical) {
      styles.height = `${this.state.height}px`
    }
    if (horizontal) {
      styles.width = `${this.state.width}px`
    }
    return styles
  }

  updateWindowDimensions() {
    this.setState({ width: window.innerWidth, height: window.innerHeight })
  }

  render() {
    const { vertical, horizontal } = this.props
    return (
      <div style={this.getStyles(vertical, horizontal)} >
        {this.props.children}
      </div>
    )
  }
}

FullArea.defaultProps = {
  horizontal: false,
  vertical: false,
}

FullArea.propTypes = {
  horizontal: PropTypes.bool,
  vertical: PropTypes.bool,
}

export default FullArea
Thclark
fuente
0

También puedes probar esto:

constructor(props) {
        super(props);
        this.state = {height: props.height, width:props.width};
      }

componentWillMount(){
          console.log("WINDOW : ",window);
          this.setState({height: window.innerHeight + 'px',width:window.innerWidth+'px'});
      }

render() {
        console.log("VIEW : ",this.state);
}
Shubham Verma
fuente