Отримайте вікно перегляду / висоту вікна в ReactJS


160

Як отримати висоту вікна перегляду в ReactJS? У звичайному JavaScript я використовую

window.innerHeight()

але використовуючи ReactJS, я не впевнений, як отримати цю інформацію. Я розумію, що це

ReactDOM.findDomNode()

працює лише для створених компонентів. Однак це не так для елемента documentабо bodyелемента, який міг би дати мені висоту вікна.

Відповіді:


245

Ця відповідь схожа на Джабрана Саїда, за винятком того, що він також обробляє розміри вікон. Я отримав це звідси .

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 });
}

3
Ви можете видалити .bind(this)аргументи зворотного виклику, оскільки він вже пов'язаний конструктором.
Scymex

1
Nitpick: код у конструкторі, ймовірно, повинен бути this.state = { width: 0, height: 0 };таким, щоб параметри стану не змінювали їх типів (якщо я правильно розумію window.innerWidth - ціле число ). Не змінюється нічого, крім полегшення розуміння коду IMHO. Дякую за відповідь!
johndodo

1
@johndodo. Уопс. Відредаговано.
крапчастийкарп

7
Чому б не this.state = { width: window.innerWidth, height: window.innerHeight };почати?
Гербус

1
Можливо, це не найкраща ідея використовувати зворотний виклик для націлювання події зміни розміру вікна, а потім повторно націлити об'єкт глобального вікна всередині зворотного виклику. Для ефективності, читабельності та умовності я збираюся оновити його, щоб використовувати задані значення подій.
GoreDefex

177

Використання гачків (реагувати 16.8.0+)

Створіть useWindowDimensionsгачок.

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

Після цього ви зможете використовувати його в таких компонентах

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

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

Робочий приклад

Оригінальна відповідь

Те саме в React, ви можете використовувати window.innerHeightдля отримання висоти поточного огляду.

Як ви можете бачити тут


2
window.innerHeight не є функцією, це властивість
Jairo

2
схоже, Кевін Даниковський відредагував відповідь і якось ця зміна була схвалена. Це зараз виправлено.
QoP

3
@FeCH він видаляє слухача подій, коли компонент відключений. Вона називається cleanupфункцією, про неї можна прочитати тут
QoP

1
Будь-які ідеї отримати той самий підхід із SSR (NextJS)?
roadev

1
@roadev в NextJS, ви також можете перевірити, чи reqпідтримується опора getInitialProps. Якщо він є, він працює на сервері, то у вас не буде змінних вікон.
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...
  }
}

Встановити реквізит

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

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

Висота вікна перегляду тепер доступна як {this.state.height} у шаблоні візуалізації


13
Це рішення не оновлюється, якщо змінити вікно браузера
speckledcarp

1
FYI, оновлення стану після монтажу компонента спричинить другий виклик рендерінгу () і може призвести до обриву властивості / макета. github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules / ...
Хаукур Крістінссон

1
@HaukurKristinsson як це перемогти?
Річард

1
@JabranSaeed чому не просто йти вперед і не встановити висоту на конструкторі, а не оновити його на кріпленні? Якщо вам потрібно взяти до уваги реквізиту ви можете по замовчуванням значення для нього , як це: height: window.innerHeight || props.height. Це не тільки спростить код, але й видалить непотрібні зміни стану.
JohnnyQ

componentWillMountбільше не рекомендується, дивіться reakctjs.org/docs/react-component.html#unsafe_componentwillmount
holmberd

26

Я щойно відредагував поточну відповідь QoP , щоб підтримати SSR та використовувати його з 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>
  );
}

Прекрасне рішення.
Джеремі Е

Я спробував це зробити з NextJS, але, здається, він має правильний розмір лише після зміни розміру екрана. Я припускаю, що це відбувається через рендерінг nextJS на стороні сервера. У вас є ідеї?
herohamp

15

Відповідь @speckledcarp чудова, але може бути нудною, якщо вам потрібна така логіка в декількох компонентах. Ви можете повторно змінити його як HOC (компонент вищого порядку) повторно використовувати щоб полегшити повторне використання цієї логіки.

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}
                />
            );
        }
    };
}

Потім у вашому головному компоненті:

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);

Ви також можете "складати" HOC, якщо у вас є інший, який потрібно використовувати, наприклад withRouter(withWindowDimensions(MyComponent))

Редагувати: Я б зараз перейшов з гачком React ( приклад вище тут ), оскільки вони вирішують деякі складніші проблеми з HOC та класами


1
Хороша робота @James
Manish

8

Я просто провів серйозний час, розгадуючи деякі речі з React та прокручуючи події / позиції - так що для тих, хто все ще шукає, ось що я знайшов:

Висоту вікна перегляду можна знайти за допомогою window.innerHeight або за допомогою document.documentElement.clientHeight. (Поточна висота вікна перегляду)

Висоту всього документа (тіла) можна знайти за допомогою window.document.body.offsetHeight.

Якщо ви намагаєтеся знайти висоту документа і знаєте, коли ви потрапили в нижню частину - ось що я придумав:

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
        });
      }
    }

(Мій навігаційний шар був 72 пікселів у фіксованому положенні, таким чином, -72, щоб отримати кращий тригер прокрутки події)

Нарешті, ось ряд команд прокрутки до console.log (), які допомогли мені активно зрозуміти математику.

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);

Вау! Сподіваюся, це комусь допоможе!


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
   </>
  )
}

1
Ласкаво просимо до переповнення стека. Скидання коду без будь-якого пояснення дуже рідко корисні. Переповнення стека - це вивчення, а не надання фрагментів для сліпого копіювання та вставки. Будь ласка, відредагуйте своє запитання та поясніть, як воно працює краще, ніж те, що надала ОП.
Кріс

2

Відповіді @speckledcarp та @Jamesl є геніальними. У моєму випадку, однак, мені знадобився компонент, висота якого могла б збільшити повну висоту вікна, що залежить від часу візуалізації…render() всього піддірева. BAAAD.

Крім того, я не був зацікавлений в отриманні значень як реквізит, але просто хотів, щоб батько divзаймав всю висоту екрана (або ширину, або і те і інше).

Тому я написав батьківський компонент, що забезпечує поділ на повну висоту (та / або ширину). Бум.

Випадок використання:

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>
    )

Ось компонент:

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

0

Ви також можете спробувати це:

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);
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.