ReactJSでビューポート/ウィンドウの高さを取得する


160

ReactJSでビューポートの高さを取得するにはどうすればよいですか?私が使用する通常のJavaScriptでは

window.innerHeight()

しかし、ReactJSを使用すると、この情報を取得する方法がわかりません。私の理解は

ReactDOM.findDomNode()

作成されたコンポーネントに対してのみ機能します。ただし、これはdocumentor body要素には当てはまりません。これにより、ウィンドウの高さがわかります。

回答:


245

この回答は、ウィンドウのサイズ変更も処理することを除いて、Jabran Saeedの回答に似ています。ここからだ。

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 2017

1
Nitpick:コンストラクター内のコードはおそらくthis.state = { width: 0, height: 0 };状態変数がそのタイプを変更しないようにする必要があります(私が正しく理解した場合、window.innerWidthはintegerです)。コードを理解しやすくする以外は何も変更しません。答えてくれてありがとう!
johndodo 2018年

1
@johndodo。おっと。編集。
speckledcarp

7
なぜthis.state = { width: window.innerWidth, height: window.innerHeight };開始するには?
ガーバス

1
おそらくそれは最善のアイデアではありません。コールバックを使用してウィンドウのサイズ変更イベントをターゲットにし、コールバック内のグローバルウィンドウオブジェクトを再度ターゲットにすることです。パフォーマンス、読みやすさ、慣例のために、指定されたイベント値を使用するように更新します。
GoreDefex

176

フックの使用(React 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
Kevin Danikowskiが回答を編集し、どういうわけかその変更が承認されたようです。現在は修正されています。
QoP 2018

3
@FeCHは、コンポーネントがマウント解除されたときにイベントリスナーを削除します。これはcleanup関数と呼ばれ、ここで
QoP

1
SSR(NextJS)で同じアプローチを得るためのアイデアはありますか?
roadev

1
NextJSの@roadevでは、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
参考までに、コンポーネントのマウント後に状態を更新すると、2番目のrender()呼び出しがトリガーされ、プロパティ/レイアウトのスラッシングが発生する可能性があります。github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/...
Haukur Kristinsson

1
@HaukurKristinssonこれを克服する方法?
Richard

1
@JabranSaeedマウントで更新するのではなく、コンストラクタに高さを設定しないでください。小道具を考慮する必要がある場合は、次のようにデフォルト値を設定できますheight: window.innerHeight || props.height。これにより、コードが簡素化されるだけでなく、不要な状態変更も削除されます。
JohnnyQ 2017

componentWillMount推奨されなくなりました。reactjs.org
docs /

25

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

素晴らしいソリューション。
ジェレミーE

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がある場合は、HOCを「スタック」することもできます。 withRouter(withWindowDimensions(MyComponent))

編集:HOCとクラスの高度な問題のいくつかを解決するため、最近はReactフックを使用します(上記の例


1
良い仕事@ジェームズ
マニッシュシャルマ

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

(私のnavbarは固定位置で72pxだったので、より良いスクロールイベントトリガーを取得するには-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);

ふew!それが誰かを助けることを願っています!


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
Stack Overflowへようこそ。説明のないコードダンプが役立つことはほとんどありません。Stack Overflowは学習に関するものであり、盲目的にコピーして貼り付けるスニペットを提供するものではありません。質問を編集して、OPが提供するものよりもどのように機能するかを説明してください。
クリス

2

@speckledcarpと@Jameslの回答はどちらも素晴らしいです。しかし、私の場合、レンダリング時に条件付きでウィンドウ全体の高さを拡張できるコンポーネントが必要でした。render()サブツリー全体が再レンダリングされます。BAAAD。

さらに、私は小道具として値を取得することに興味がなかったが、単に親が欲しかった div画面全体の高さ(または幅、あるいはその両方)を占めるが必要でした。

そのため、完全な高さ(および/または幅)の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);
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.