Nhận khung nhìn / chiều cao cửa sổ trong ReactJS


160

Làm cách nào để có được chiều cao khung nhìn trong ReactJS? Trong JavaScript bình thường tôi sử dụng

window.innerHeight()

nhưng sử dụng ReactJS, tôi không biết làm thế nào để có được thông tin này. Hiểu biết của tôi là

ReactDOM.findDomNode()

Chỉ hoạt động cho các thành phần được tạo. Tuy nhiên đây không phải là trường hợp của phần tử documenthoặc bodyphần tử có thể cho tôi chiều cao của cửa sổ.

Câu trả lời:


245

Câu trả lời này tương tự như của Jabran Saeed, ngoại trừ nó cũng xử lý thay đổi kích thước cửa sổ. Tôi đã nhận nó từ đây .

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
Bạn có thể xóa .bind(this)khỏi các đối số gọi lại vì nó đã bị ràng buộc bởi hàm tạo.
Scymex

1
Nitpick: code trong constructor có lẽ this.state = { width: 0, height: 0 };nên để các vars trạng thái không thay đổi kiểu của chúng (nếu tôi hiểu chính xác window.innerWidth là số nguyên ). Không thay đổi bất cứ điều gì ngoại trừ làm cho mã dễ hiểu hơn IMHO. Cảm ơn câu trả lời!
johndodo

1
@johndodo. Rất tiếc. Đã chỉnh sửa.
speckledcarp

7
Tại sao không this.state = { width: window.innerWidth, height: window.innerHeight };bắt đầu?
Gerbus

1
Có lẽ đó không phải là ý tưởng tốt nhất, sử dụng một cuộc gọi lại để nhắm mục tiêu sự kiện thay đổi kích thước của cửa sổ và sau đó nhắm mục tiêu lại đối tượng cửa sổ toàn cầu bên trong cuộc gọi lại. Để thực hiện, khả năng đọc và quy ước, tôi sẽ cập nhật nó để sử dụng các giá trị sự kiện đã cho.
GoreDefex

176

Sử dụng móc (Phản ứng 16.8.0+)

Tạo một useWindowDimensionscái móc.

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

Và sau đó, bạn sẽ có thể sử dụng nó trong các thành phần của bạn như thế này

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

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

Ví dụ làm việc

Câu trả lời gốc

Tương tự như vậy trong React, bạn có thể sử dụng window.innerHeightđể có được chiều cao của khung nhìn hiện tại.

Như bạn có thể thấy ở đây


2
window.innerHeight không phải là một chức năng, nó là một tài sản
Jairo

2
Có vẻ như Kevin Danikowski đã chỉnh sửa câu trả lời và bằng cách nào đó sự thay đổi đó đã được chấp thuận. Bây giờ nó đã được sửa.
QoP

3
@FeCH nó loại bỏ trình nghe sự kiện khi thành phần không được đếm. Nó được gọi là cleanuphàm, bạn có thể đọc về nó ở đây
QoP

1
Bạn có ý tưởng nào để có cùng cách tiếp cận với SSR (NextJS) không?
roadev

1
@roadev tại NextJS, bạn cũng có thể kiểm tra xem reqprop có sẵn không getInitialProps. Nếu có, nó đang chạy trên máy chủ, thì bạn sẽ không có biến cửa sổ.
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...
  }
}

Đặt đạo cụ

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

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

chiều cao khung nhìn hiện có sẵn dưới dạng {this.state.height} trong mẫu kết xuất


13
Giải pháp này không cập nhật nếu cửa sổ trình duyệt bị thay đổi kích thước
speckledcarp

1
FYI, cập nhật trạng thái sau khi gắn kết thành phần sẽ kích hoạt lệnh gọi kết xuất thứ hai () và có thể dẫn đến phá hủy thuộc tính / bố cục. github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/
gợi

1
@HaukurKristinsson làm thế nào để khắc phục điều này?
Richard

1
@JabranSaeed tại sao không đi trước và thiết lập chiều cao trên hàm tạo thay vì cập nhật nó trên mount? Nếu bạn cần cân nhắc các đạo cụ, bạn có thể mặc định giá trị của nó như thế này : height: window.innerHeight || props.height. Điều này sẽ không chỉ đơn giản hóa mã mà còn loại bỏ các thay đổi trạng thái không cần thiết.
JohnnyQ

componentWillMountkhông còn được khuyến nghị, xem Reacjs.org/docs/react-component.html#unsafe_componentwillmount
holmberd

25

Tôi vừa chỉnh sửa câu trả lời hiện tại của QoP để hỗ trợ SSR và sử dụng nó với 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>
  );
}

Giải pháp tuyệt vời.
Jeremy E

15

Câu trả lời của @speckledcarp là tuyệt vời, nhưng có thể tẻ nhạt nếu bạn cần logic này trong nhiều thành phần. Bạn có thể cấu trúc lại nó dưới dạng HOC (thành phần bậc cao hơn) để làm cho logic này dễ sử dụng hơn.

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

Sau đó, trong thành phần chính của bạn:

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

Bạn cũng có thể "xếp" các HOC nếu bạn cần sử dụng một cái khác, vd withRouter(withWindowDimensions(MyComponent))

Chỉnh sửa: Hôm nay tôi sẽ sử dụng hook React ( ví dụ ở trên ), vì chúng giải quyết một số vấn đề nâng cao với HOC và các lớp


1
Làm tốt lắm @James
Manish sharma

8

Tôi vừa dành thời gian nghiêm túc để tìm ra một số thứ với React và cuộn các sự kiện / vị trí - vì vậy đối với những người vẫn đang tìm kiếm, đây là những gì tôi tìm thấy:

Có thể tìm thấy chiều cao của khung nhìn bằng cách sử dụng window.innerHeight hoặc bằng cách sử dụng document.documentEuity.clientHeight. (Chiều cao khung nhìn hiện tại)

Chiều cao của toàn bộ tài liệu (phần thân) có thể được tìm thấy bằng window.document.body.offsetHeight.

Nếu bạn đang cố gắng tìm chiều cao của tài liệu và biết khi nào bạn chạm đáy - đây là những gì tôi nghĩ ra:

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

(Thanh điều hướng của tôi là 72px ở vị trí cố định, do đó, -72 để có trình kích hoạt sự kiện cuộn tốt hơn)

Cuối cùng, đây là một số lệnh cuộn đến console.log (), giúp tôi chủ động tìm ra toán học của mình.

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

Phù! Hy vọng nó sẽ giúp được ai đó!


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
Chào mừng bạn đến với Stack Overflow. Mã bãi mà không có bất kỳ lời giải thích hiếm khi hữu ích. Stack Overflow là về học tập, không cung cấp đoạn trích để sao chép và dán một cách mù quáng. Vui lòng chỉnh sửa câu hỏi của bạn và giải thích cách nó hoạt động tốt hơn những gì OP cung cấp.
Chris

2

Câu trả lời của @speckledcarp và @Jamesl đều tuyệt vời. Tuy nhiên, trong trường hợp của tôi, tôi cần một thành phần có chiều cao có thể mở rộng toàn bộ chiều cao cửa sổ, có điều kiện vào thời gian kết xuất .... nhưng gọi HOC trongrender() khi hiển thị lại toàn bộ cây con. BAAAD.

Thêm vào đó, tôi không quan tâm đến việc lấy các giá trị làm đạo cụ mà chỉ muốn có cha mẹ div chiếm toàn bộ chiều cao màn hình (hoặc chiều rộng hoặc cả hai).

Vì vậy, tôi đã viết một thành phần Parent cung cấp div chiều cao (và / hoặc chiều rộng) đầy đủ. Bùng nổ.

Một trường hợp sử dụng:

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

Đây là thành phần:

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

Bạn cũng có thể thử điều này:

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);
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.