ReactJS - 获取元素的高度

IT技术 javascript reactjs
2021-04-12 02:34:00

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>

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

结果

Size: 36px but it should be 18px after the render

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

6个回答

以下是使用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'))

您可以在此处找到运行示例:https : //codepen.io/bassgang/pen/povzjKw

这有效,但我收到了 Airbnb 样式指南的几个 eslint 错误:<div ref={ divElement => this.divElement = divElement}>{children}</div>抛出“[eslint] 箭头函数不应返回赋值。(no-return-assign)”并this.setState({ height });抛出“[eslint] Do not use setState in componentDidMount(react/no- did-mount-set-state)”。任何人都有符合样式指南的解决方案?
2021-05-29 02:34:00
将赋值括在大括号中,使其表现为函数(而不是表达式),如下所示 ref={ divElement => {this.divElement = divElement}}
2021-06-03 02:34:00
很好的解决方案。但不适用于响应式设计。如果桌面的标题高度为 50 像素,并且用户缩小窗口大小,现在高度变为 100 像素,则此解决方案不会采用更新的高度。他们需要刷新页面才能获得更改后的效果。
2021-06-12 02:34:00
这应该是公认的答案:) 此外,如果您想在元素更新后获取元素的大小,也可以使用该方法componentDidUpdate
2021-06-16 02:34:00
有没有其他方法可以在这个例子中在 componentDidMount 中调用 this.setState() ?
2021-06-19 02:34:00

对于那些对使用 感兴趣的人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>
  )
}
我刚刚实施了一个使用我建议的两个项目的解决方案。它们似乎运行良好,但您可能知道这些选择的一些缺点吗?谢谢你的帮助!
2021-05-22 02:34:00
@JasonFrank 好问题。1) useEffect 和 useLayoutEffect 在布局和绘制后都会被触发。但是,useLayoutEffect 将在下一次绘制之前同步触发。我想说,如果你真的需要视觉一致性,那么使用 useLayoutEffect,否则,useEffect 就足够了。2)你是对的!在功能组件中 createRef 将在每次渲染组件时创建一个新的 ref。使用 useRef 是更好的选择。我会更新我的答案。谢谢!
2021-05-25 02:34:00
@faia20 您可能想要选择这个更现代的答案。
2021-05-29 02:34:00
我正在设置组件的尺寸useEffect(() => setDimensions({width: popup.current.clientWidth, height: popup.current.clientHeight})),我的 IDE (WebStorm) 建议我这样做:ESLint:React Hook useEffect 包含对“setDimensions”的调用。如果没有依赖项列表,这可能会导致无限的更新链。要解决此问题,请将 [] 作为第二个参数传递给 useEffect Hook。(react-hooks/exhaustive-deps),所以[]作为第二个参数传递给你useEffect
2021-06-01 02:34:00
感谢您的回答 - 它帮助我开始。2个问题:(1)对于这些布局测量任务,我们应该使用useLayoutEffect而不是useEffect吗?文档似乎表明我们应该这样做。请参阅此处的“提示”部分:reactjs.org/docs/hooks-effect.html#detailed-explanation (2) 对于这些我们只需要引用子元素的情况,我们应该使用useRef代替createRef吗?文档似乎表明useRef更适合此用例。请参阅: reactjs.org/docs/hooks-reference.html#useref
2021-06-11 02:34:00

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

您需要componentDidMount在 render 方法之后钩入哪个运行。在那里,您将获得元素的实际高度。

var DivSize = React.createClass({
    getInitialState() {
    return { state: 0 };
  },

  componentDidMount() {
    const height = document.getElementById('container').clientHeight;
    this.setState({ height });
  },

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

ReactDOM.render(
  <DivSize />,
  document.getElementById('container')
);
<script src="https://facebook.github.io/react/js/jsfiddle-integration-babel.js"></script>

<div id="container">
<p>
jnknwqkjnkj<br>
jhiwhiw (this is 36px height)
</p>
    <!-- This element's contents will be replaced with your component. -->
</div>
恕我直言,组件不应该知道其容器的名称
2021-05-27 02:34:00
这是错误的!不是一个好习惯。查看其他建议的解决方案。
2021-05-31 02:34:00
不正确。见下面保罗文森特北岗的回答
2021-06-09 02:34:00

除了使用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>
  )
}

您还希望在元素上使用 refs 而不是 using document.getElementById,它只是稍微更强大一些。

@doublejosh 基本上你是对的,但是如果你需要混合angularJs并且react从一个迁移到另一个时该怎么办?有些情况下确实需要直接 DOM 操作
2021-05-28 02:34:00