ReactJS - 获取元素的高度

fai*_*a20 87 javascript reactjs

在React呈现该元素后,如何获得元素的高度?

HTML

<div id="container">
<!-- This element's contents will be replaced with your component. -->
<p>
jnknwqkjnkj<br>
jhiwhiw (this is 36px height)
</p>
</div>
Run Code Online (Sandbox Code Playgroud)

ReactJS

var DivSize = React.createClass({

  render: function() {
    let elHeight = document.getElementById('container').clientHeight
    return <div className="test">Size: <b>{elHeight}px</b> but it should be 18px after the render</div>;
  }
});

ReactDOM.render(
  <DivSize />,
  document.getElementById('container')
);
Run Code Online (Sandbox Code Playgroud)

结果

Size: 36px but it should be 18px after the render
Run Code Online (Sandbox Code Playgroud)

它正在计算渲染前的容器高度(36px).我想在渲染后获得高度.在这种情况下,正确的结果应该是18px.

https://jsfiddle.net/69z2wepo/29800/

Pau*_*ang 132

以下是使用ref的最新ES6示例.

请记住,我们必须使用React类组件,因为我们需要访问Lifecycle方法,componentDidMount()因为我们只能确定元素在DOM中呈现后的高度.

import React, {Component} from 'react'
import {render} from 'react-dom'

class DivSize extends Component {

  constructor(props) {
    super(props)

    this.state = {
      height: 0
    }
  }

  componentDidMount() {
    const height = this.divElement.clientHeight;
    this.setState({ height });
  }

  render() {
    return (
      <div 
        className="test"
        ref={ (divElement) => { this.divElement = divElement } }
      >
        Size: <b>{this.state.height}px</b> but it should be 18px after the render
      </div>
    )
  }
}

render(<DivSize />, document.querySelector('#container'))
Run Code Online (Sandbox Code Playgroud)

你可以在这里找到运行的例子:https://www.webpackbin.com/bins/-KkP1HhC_tW4FeoYSuDe

  • 将赋值包装在大括号中,使其表现为函数(而不是表达式),如`ref = {divElement => {this.divElement = divElement}}` (7认同)
  • 这有效,但我得到Airbnb样式指南的几个eslint错误:`<div ref = {divElement => this.divElement = divElement}> {children} </ div>`throws"[eslint]箭头函数不应该返回赋值.( no-return-assign)"和`this.setState({height});`throws"[eslint]不要在componentDidMount中使用setState(react/no-did-mount-set-state)".任何人都有符合样式指南的解决方案? (5认同)
  • 很好的解决方案。但不适用于响应式设计。如果桌面的标题高度为 50 像素,并且用户缩小窗口大小,现在高度变为 100 像素,则此解决方案不会采用更新的高度。他们需要刷新页面才能获得更改后的效果。 (4认同)
  • 这可能是接受的答案:)此外,如果你想在元素更新后获得元素的大小,你也可以使用方法`componentDidUpdate`. (3认同)
  • 在此示例中,除了在componentDidMount中调用this.setState()之外,还有其他方法吗? (3认同)
  • @TheCoder 检测窗口大小调整:/sf/ask/2216325331/ (2认同)

Mr.*_* 14 41

对于那些有兴趣使用的人react hooks,这可能会帮助您入门。

import React, { useState, useEffect, useRef } from 'react'

export default () => {
  const [height, setHeight] = useState(0)
  const ref = useRef(null)

  useEffect(() => {
    setHeight(ref.current.clientHeight)
  })

  return (
    <div ref={ref}>
      {height}
    </div>
  )
}
Run Code Online (Sandbox Code Playgroud)

  • 感谢您的回答-它帮助我入门。但是有两个问题:(1)对于这些布局测量任务,我们应该使用`useLayoutEffect`而不是`useEffect`吗?该文档似乎表明我们应该这样做。请参阅此处的“提示”部分:https://reactjs.org/docs/hooks-effect.html#detailed-explanation(2)对于这些情况,我们只需要引用子元素,则应使用`useRef`。而不是`createRef`?文档似乎表明`useRef`更适合此用例。请参阅:https://reactjs.org/docs/hooks-reference.html#useref (5认同)
  • @JasonFrank好问题。1)useEffect和useLayoutEffect都将在布局和绘制后被触发。但是,useLayoutEffect将在下一次绘制之前同步触发。我想说的是,如果您确实需要视觉一致性,请使用useLayoutEffect,否则,useEffect就足够了。2)你是对的!在功能组件中,每次渲染组件时,createRef都会创建一个新的ref。使用useRef是更好的选择。我将更新我的答案。谢谢! (3认同)

And*_*yco 26

看到这个小提琴(实际上更新了你的)

你需要挂钩componentDidMount在render方法之后运行.在那里,你得到元素的实际高度.

  • 不正确.请参阅Paul Vincent Beigang的回答 (7认同)

cha*_*rri 15

除了使用document.getElementById(...),更好(最新)的解决方案是使用 React useRef钩子来存储对组件/元素的引用,并结合使用在组件渲染时触发的useEffect钩子。

import React, {useState, useEffect, useRef} from 'react';

export default App = () => {
  const [height, setHeight] = useState(0);
  const elementRef = useRef(null);

  useEffect(() => {
    setHeight(elementRef.current.clientHeight);
  }, []); //empty dependency array so it only runs once at render

  return (
    <div ref={elementRef}>
      {height}
    </div>
  )
}
Run Code Online (Sandbox Code Playgroud)


yoy*_*nno 8

你也想在元素上使用ref而不是使用document.getElementById,它只是一个稍微强大的东西.


Dan*_*ani 8

我 2020 年(或 2019 年)的答案

import React, {Component, useRef, useLayoutEffect} from 'react';
import { useDispatch } from 'react-redux';
import { Toast, ToastBody, ToastHeader } from 'reactstrap';

import {WidgetHead} from './WidgetHead';

export const Widget = ({title, toggle, reload, children, width, name}) => {
    let myself = useRef(null);
    const dispatch = useDispatch();
    useLayoutEffect(()=>{
        if (myself.current) {
            const height = myself.current.clientHeight
            dispatch({type:'GRID_WIDGET_HEIGHT', widget:name, height})
        }
    }, [myself.current, myself.current?myself.current.clientHeight:0])

    return (
        <Toast innerRef={myself}>
            <WidgetHead title={title}
                toggle={toggle}
                reload={reload} />
            <ToastBody>
            {children}
            </ToastBody>
        </Toast>
    )
}
Run Code Online (Sandbox Code Playgroud)

让你的想象力,什么是在这里失踪(WidgetHead),reactstrap是你可以找到关于故宫:更换innerRefref的传统的DOM元素(说<div>)。

useEffect 或 useLayoutEffect

据说最后一个是同步变化的

useLayoutEffect(或useEffect)第二个参数

第二个参数是一个数组,它在执行第一个参数中的函数之前被检查。

我用了

[myself.current,self.current?myself.current.clientHeight:0]

因为在渲染之前我自己.current是空的,这是一件好事,不要检查,最后的第二个参数myself.current.clientHeight是我想要检查的变化。

我在这里解决的(或试图解决的)

我在这里解决了网格上的小部件根据自己的意愿改变其高度的问题,并且网格系统应该具有足够的弹性以做出反应(https://github.com/STRML/react-grid-layout)。

  • 很好的答案,但会从更简单的例子中受益。基本上是whiteknight的答案,但是用`useLayoutEffect`和实际的div来绑定引用。 (3认同)

Shu*_*man 8

它可能显示为零。setTimeout 有助于获取正确的值并更新状态。

import React, { useState, useEffect, useRef } from 'react'
    
    export default () => {
      const [height, setHeight] = useState(0)
      const ref= useRef(null)
    
      useEffect(() => {
       if(elemRef.current.clientHeight){
         setTimeout(() => {
           setHeight(ref.current.clientHeight) 
         }, 1000)
       }
      })
    
      return (
        <div ref={ref}>
          {height}
        </div>
      )
    }
Run Code Online (Sandbox Code Playgroud)


iam*_*ain 6

与钩子一起使用:

如果您的内容尺寸在加载后发生变化,这个答案将会很有帮助。

onreadystatechange:当属于元素或 HTML 文档的数据的加载状态发生更改时发生。当页面内容的加载状态发生更改时,将在 HTML 文档上触发 onreadystatechange 事件。

import {useState, useEffect, useRef} from 'react';
const ref = useRef();
useEffect(() => {
    document.onreadystatechange = () => {
      console.log(ref.current.clientHeight);
    };
  }, []);
Run Code Online (Sandbox Code Playgroud)

我试图使用嵌入的 YouTube 视频播放器,其尺寸在加载后可能会发生变化。