ChatGPT解决这个技术问题 Extra ChatGPT

在 ReactJS 中获取视口/窗口高度

如何在 ReactJS 中获取视口高度?在我使用的普通 JavaScript 中

window.innerHeight()

但是使用 ReactJS,我不确定如何获取这些信息。我的理解是

ReactDOM.findDomNode()

仅适用于创建的组件。但是,对于 documentbody 元素,情况并非如此,这可能会给我窗口的高度。


Q
QoP

使用 Hooks (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>
  );
}

Working example

原始答案

在 React 中也是一样,你可以使用 window.innerHeight 来获取当前视口的高度。

如您所见here


window.innerHeight 不是一个函数,它是一个属性
看起来凯文·丹尼科夫斯基(Kevin Danikowski)编辑了答案,并且以某种方式批准了该更改。现在已经修好了。
@FeCH 它会在组件卸载时删除事件侦听器。它被称为 cleanup 函数,您可以阅读它here
有什么想法可以使用 SSR (NextJS) 获得相同的方法吗?
这么好的答案。希望更多的人写这样的 stackoverflow 答案,而不是发布 npm 模块。
s
speckledcarp

这个答案类似于 Jabran Saeed 的,除了它也处理窗口大小调整。我从 here 得到的。

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

您可以从回调参数中删除 .bind(this),因为它已经被构造函数绑定。
Nitpick:构造函数中的代码可能应该是 this.state = { width: 0, height: 0 };,这样状态变量就不会改变它们的类型(如果我理解正确的话 window.innerWidth is integer)。除了使代码更容易理解恕我直言之外,不会改变任何东西。感谢你的回答!
为什么不从 this.state = { width: window.innerWidth, height: window.innerHeight }; 开始?
@Gerbus:+1。这就是它在初始页面加载时对我有用的原因。
使用回调来定位窗口的调整大小事件,然后在回调中重新定位全局窗口对象,这可能不是最好的主意。为了性能、可读性和约定,我将更新它以使用给定的事件值。
g
giovannipds

我刚刚编辑了 QoPcurrent answer 以支持 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 服务器端渲染。你有什么想法?
这个答案不起作用,因为它不会在不调整大小的情况下设置大小。请参阅我之前的评论,请进行编辑
@giovannipds 抱歉,我一定误读了它,这行得通
嗨乔瓦尼,谢谢你的回答。是的,我了解您的代码在做什么。我的意思是向其他人表明,使用最新版本的 Next 会触发警告(我同意你的观点,它仍然有效,只是警告)。我在文档中的任何地方都找不到以下方法: 1. 在 Next 中轻松忽略此警告。 2. 调整代码使其不会触发它。对于以后,如果您有任何指示,请告诉我;-)
@MrWashington 如果可以的话,例如做一个回购/测试用例,我会和你核实。
C
Community
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}


如果调整浏览器窗口大小,此解决方案不会更新
仅供参考,在组件挂载后更新状态将触发第二次 render() 调用,并可能导致属性/布局抖动。 github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/…
@HaukurKristinsson 如何克服这个问题?
@JabranSaeed 为什么不直接在构造函数上设置高度而不是在安装时更新它?如果您需要考虑道具,您可以像这样默认值:height: window.innerHeight || props.height。这不仅会简化代码,还会消除不必要的状态更改。
不再推荐 componentWillMount,请参阅 reactjs.org/docs/react-component.html#unsafe_componentwillmount
H
HoldOffHunger

我使用 React Hooks 和调整大小功能找到了 QoP 和斑点卡的简单组合,代码行数略少:

const [width, setWidth]   = useState(window.innerWidth);
const [height, setHeight] = useState(window.innerHeight);
const updateDimensions = () => {
    setWidth(window.innerWidth);
    setHeight(window.innerHeight);
}
useEffect(() => {
    window.addEventListener("resize", updateDimensions);
    return () => window.removeEventListener("resize", updateDimensions);
}, []);

哦,是的,请确保 resize 事件是双引号,而不是单引号。那个让我有点;)


单引号有什么问题?
并处理此示例中常见的 window is not defined 问题?
为避免未定义窗口可以这样做: const [width, setWidth] = React.useState(0) 和 React.useEffect(() => { if (typeof window !== 'undefined') { setWidth(window.innerWidth )
J
James L.

@speckledcarp 的答案很棒,但如果您在多个组件中需要此逻辑,可能会很乏味。您可以将其重构为 HOC (higher order component) 以使此逻辑更易于重用。

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

编辑:现在我会使用 React 钩子(example above here),因为它们解决了一些 advanced issues with HOCs and classes


M
Matthew Barnden

用一点打字稿

从“反应”导入 { useState, useEffect };界面 WindowDimentions { 宽度:数字;高度:数字; } function getWindowDimensions(): WindowDimentions { const { innerWidth: width, innerHeight: height } = window;返回{宽度,高度}; } 导出默认函数 useWindowDimensions(): WindowDimentions { const [windowDimensions, setWindowDimensions] = useState( getWindowDimensions() ); useEffect(() => { function handleResize(): void { setWindowDimensions(getWindowDimensions()); } window.addEventListener('resize', handleResize); return (): void => window.removeEventListener('resize', handleResize) ; }, []);返回窗口尺寸; }


A
Aklesh Sakunia

添加这个以实现多样性和干净的方法。

此代码使用功能样式方法。如其他答案中所述,我使用了 onresize 而不是 addEventListener 。

import { useState, useEffect } from "react";

export default function App() {
  const [size, setSize] = useState({
    x: window.innerWidth,
    y: window.innerHeight
  });
  const updateSize = () =>
    setSize({
      x: window.innerWidth,
      y: window.innerHeight
    });
  useEffect(() => (window.onresize = updateSize), []);
  return (
    <>
      <p>width is : {size.x}</p>
      <p>height is : {size.y}</p>
    </>
  );
}

如果您收到类似以下错误的小更新:“未定义窗口”。将状态 x 和 y 的初始值设置为 0,一切正常。
V
Vega

我只是花了一些时间用 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
        });
      }
    }

(我的导航栏是 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);

哇!希望它可以帮助某人!


f
foad abdollahi

使用钩子:

在这里使用 useLayoutEffect 更有效:

import { useState, useLayoutEffect } from 'react';

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

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

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

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

  return windowDimensions;
}

用法:

const { height, width } = useWindowDimensions();

不适用于 Next.js
A
Aljohn Yamaro

再会,

我知道我参加这个聚会迟到了,但让我告诉你我的答案。

const [windowSize, setWindowSize] = useState(null)

useEffect(() => {
    const handleResize = () => {
        setWindowSize(window.innerWidth)
    }

    window.addEventListener('resize', handleResize)

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

有关详细信息,请访问 https://usehooks.com/useWindowSize/


您是否应该在效果中调用 handleResize() 以设置原始浏览器窗口大小? window.innerHeight 也将获得高度
J
Joabe
// 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
   </>
  )
}

欢迎来到堆栈溢出。没有任何解释的代码转储很少有帮助。 Stack Overflow 是关于学习的,而不是提供片段来盲目复制和粘贴。请edit您的问题并解释它如何比 OP 提供的更好。
小心,此代码永远不会删除它创建的事件侦听器。 stackoverflow.com/a/36862446/867600 是一种更好的挂钩方法。
J
Jason Jin

您可以像这样创建自定义挂钩:useWindowSize()

import { useEffect, useState } from "react";
import { debounce } from "lodash";

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

export function useWindowSize(delay = 0) {
  const [windowDimensions, setWindowDimensions] = useState(
    getWindowDimensions()
  );

  useEffect(() => {
    function handleResize() {
      setWindowDimensions(getWindowDimensions());
    }
    const debouncedHandleResize = debounce(handleResize, delay);
    window.addEventListener("resize", debouncedHandleResize);
    return () => window.removeEventListener("resize", debouncedHandleResize);
  }, [delay]);

  return windowDimensions;
}

t
thclark

@speckledcarp 和 @Jamesl 的回答都很出色。然而,在我的情况下,我需要一个高度可以扩展整个窗口高度的组件,在渲染时有条件......但是在 render() 内调用 HOC 会重新渲染整个子树。巴阿德。

另外,我对获取值作为道具不感兴趣,而只是想要一个占据整个屏幕高度(或宽度,或两者)的父 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

G
Gunzz

通过将 getWindowDimensions 函数包装在 useCallback 中,我更新了代码稍有变化

import { useCallback, useLayoutEffect, useState } from 'react';

export default function useWindowDimensions() {

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

    const getWindowDimensions = useCallback(() => {
        const windowWidth = hasWindow ? window.innerWidth : null;
        const windowHeight = hasWindow ? window.innerHeight : null;

        return {
            windowWidth,
            windowHeight,
        };
    }, [hasWindow]);

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

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

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

    return windowDimensions;
}

该答案实际上是先前答案的副本
Y
Yaser AZ

这是您可以实现它并在 React 功能组件中实时获取窗口宽度和高度的方法:

import React, {useState, useEffect} from 'react' 
const Component = () => {
  const [windowWidth, setWindowWidth] = useState(0)
  const [windowHeight, setWindowHeight] = useState(0)
  
  useEffect(() => {
    window.addEventListener('resize', e => {
      setWindowWidth(window.innerWidth);
    });
  }, [window.innerWidth]);

  useEffect(() => {
    window.addEventListener('resize', e => {
      setWindowHeight(window.innerHeight);
    });
  }, [window.innerHeight]);

  return(
    <h3>Window width is: {windowWidth} and Height: {windowHeight}</h3>
  )
}

S
Shubham Verma

你也可以试试这个:

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

G
GavinBelson

即使在调整窗口大小后,也可以将当前尺寸保持在状态的简单方法:

//set up defaults on page mount
componentDidMount() {
  this.state = { width: 0, height: 0 };
  this.getDimensions(); 

  //add dimensions listener for window resizing
  window.addEventListener('resize', this.getDimensions); 
}

//remove listener on page exit
componentWillUnmount() {
  window.removeEventListener('resize', this.getDimensions); 
}

//actually set the state to the window dimensions
getDimensions = () => {
  this.setState({ width: window.innerWidth, height: window.innerHeight });
  console.log(this.state);
}

b
bren

使用 useEffect 很简单

useEffect(() => {
    window.addEventListener("resize", () => {
        updateDimention({ 
            ...dimension, 
            width: window.innerWidth, 
            height: window.innerHeight 
        });
        console.log(dimension);
    })
})

佚名

作为答案: bren 但将 useEffect 挂钩到 [window.innerWidth]

const [dimension, updateDimention] = useState();
  
  useEffect(() => {
    window.addEventListener("resize", () => {
        updateDimention({ 
            ...dimension, 
            width: window.innerWidth, 
            height: window.innerHeight 
        });
       
    })
},[window.innerWidth]);

 console.log(dimension);

您的答案可以通过额外的支持信息得到改进。请edit添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。您可以找到有关如何写出好答案的更多信息in the help center
p
pl709

React Native Web 有一个可以使用的 useWindowDimensions 钩子:

    import { useWindowDimensions } from "react-native";
    const dimensions = useWindowDimensions()

适用于 react-native-web 或 expo *
J
Jonatan Kruszewski

在这里,您可以将投票最多的答案包装在一个节点包(经过测试,打字稿)中,以供使用。

安装:

npm i @teambit/toolbox.react.hooks.get-window-dimensions

用法:

import React from 'react';
import { useWindowDimensions } from '@teambit/toolbox.react.hooks.get-window-dimensions';

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

  return (
    <>
      <h1>Window size</h1>
      <p>Height: {height}</p>
      <p>Width: {width}</p>
    </>
  );
};