ReactJS - एक तत्व की ऊँचाई प्राप्त करें


121

रिएक्ट करने के बाद मैं उस तत्व की ऊँचाई कैसे प्राप्त कर सकता हूँ?

एचटीएमएल

<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 होना चाहिए। jsfiddle


1
यह एक प्रतिक्रिया प्रश्न नहीं है, बल्कि एक जावास्क्रिप्ट और डोम प्रश्न है। आपको यह पता लगाने की कोशिश करनी चाहिए कि आपके तत्व की अंतिम ऊंचाई का पता लगाने के लिए आपको किस DOM इवेंट का उपयोग करना चाहिए। ईवेंट हैंडलर में, आप setStateस्टेट वैरिएबल को ऊंचाई मान असाइन करने के लिए उपयोग कर सकते हैं ।
मोस्टरुश

जवाबों:


28

इस फिडल को देखें (वास्तव में आपके अपडेट किया गया है)

आपको हुक करने की आवश्यकता है componentDidMountजिसमें रेंडर विधि के बाद चलाया जाता है। वहां, आपको तत्व की वास्तविक ऊंचाई मिलती है।

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>

15
गलत। नीचे पॉल विंसेंट
बेइगंग

1
IMHO, एक घटक अपने कंटेनर का नाम पता नहीं करना चाहिए
एन्ड्रेस

156

निम्नलिखित रेफरी का उपयोग करते हुए ES6 उदाहरण के लिए एक तारीख है

याद रखें कि हमें एक रीक्ट क्लास घटक का उपयोग करना होगा 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


6
यह काम करता है, लेकिन मैं Airbnb styleguide के लिए कई eslint त्रुटियों हो रही है: <div ref={ divElement => this.divElement = divElement}>{children}</div>थ्रो "[eslint] तीर समारोह काम लौट जाना नहीं (नो-वापसी असाइन)।" और this.setState({ height });फेंकता है "[eslint] (प्रतिक्रिया componentDidMount में setState का उपयोग नहीं करते / नहीं- था माउंट-सेट-राज्य) "। किसी को भी एक स्टाइल-अनुवर्ती समाधान मिला?
तिमो

7
असाइनमेंट को ब्रेसिज़ में लपेटें ताकि यह एक फ़ंक्शन (एक अभिव्यक्ति के बजाय) के रूप में व्यवहार करे, जैसेref={ divElement => {this.divElement = divElement}}
टेलेस्टिपिस्ट

3
यह बोया गया स्वीकृत उत्तर होगा :) इसके अलावा, यदि आप तत्व को अपडेट करने के बाद तत्व का आकार प्राप्त करना चाहते हैं, तो आप विधि का भी उपयोग कर सकते हैं componentDidUpdate
jjimenez

4
क्या इस उदाहरण के साथ कंपोनेंटडीडमाउंट में इस.सेटस्टैट () को कॉल करने का विकल्प है?
danjones_mcr

3
अच्छा समाधान। लेकिन उत्तरदायी डिजाइनों के लिए काम नहीं करेगा। यदि डेस्कटॉप के लिए हेडर की ऊंचाई 50px थी, और उपयोगकर्ता विंडो का आकार छोटा कर देता है, और अब ऊंचाई 100px हो जाती है, तो यह समाधान अद्यतन ऊंचाई नहीं लेगा। बदले हुए प्रभाव को प्राप्त करने के लिए उन्हें पृष्ठ को रीफ्रेश करने की आवश्यकता है।
theCoder

97

जो लोग उपयोग करने में रुचि रखते हैं 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>
  )
}

11
आपके उत्तर के लिए धन्यवाद - इससे मुझे शुरुआत करने में मदद मिली। 2 प्रश्न हालांकि: (1) इन लेआउट-मापने के कार्यों के लिए, के useLayoutEffectबजाय हमें उपयोग करना चाहिए useEffect? डॉक्स यह संकेत देते हैं कि हमें चाहिए। यहां "टिप" अनुभाग देखें: reactjs.org/docs/hooks-effect.html#detailed-explanation (2) इन मामलों के लिए जहां हमें सिर्फ एक बच्चे के तत्व के संदर्भ की आवश्यकता है, क्या हमें useRefइसके बजाय उपयोग करना चाहिए createRef? डॉक्स इंगित करते हैं useRefकि इस उपयोग के मामले के लिए अधिक उपयुक्त है। देखें: reactjs.org/docs/hooks-reference.html#useref
जेसन फ्रैंक

मैंने अभी एक समाधान लागू किया है जो उन दो वस्तुओं का उपयोग करता है जो मैं सुझा रहा हूं। वे अच्छी तरह से काम करने लगते हैं, लेकिन आप इन विकल्पों के बारे में कुछ डाउनसाइड जान सकते हैं? आपकी सहायताके लिए धन्यवाद!
जेसन फ्रैंक

4
@JasonFrank अच्छे प्रश्न। 1) लेआउट और पेंट के बाद दोनों का उपयोग और उपयोग लाइएटआउट को निकाल दिया जाएगा। हालाँकि, useLayoutEffect अगले पेंट से पहले सिंक्रोनस रूप से फायर करेगा। मैं कहूंगा कि अगर आपको वास्तव में दृश्य स्थिरता की आवश्यकता है, तो useLayoutEffect का उपयोग करें, अन्यथा, useEffect को पर्याप्त होना चाहिए। 2) आप इसके बारे में सही हैं! एक कार्यात्मक घटक में createRef हर बार एक नया रेफरी बनाएगा जब घटक को रेंडर किया जा रहा है। UseRef का उपयोग करना बेहतर विकल्प है। मैं अपना जवाब अपडेट करूंगा। धन्यवाद!
मि। १४

इससे मुझे यह समझने में मदद मिली कि हुक के साथ रेफ का उपयोग कैसे किया जाता है। मैंने useLayoutEffectअन्य टिप्पणियों को पढ़ने के बाद यहाँ जाना समाप्त कर दिया। अच्छा काम करने लगता है। :)
गुडी डूडी

1
मैं अपने घटक के आयाम स्थापित कर रहा था useEffect(() => setDimensions({width: popup.current.clientWidth, height: popup.current.clientHeight})), और मेरी आईडीई (वेबस्टॉर्म) ने मुझे यह सुझाव दिया था: ESLint: रिएक्ट हुक का उपयोग करें इसमें 'सेटडिमेंशन' के लिए एक कॉल शामिल है। निर्भरता की सूची के बिना, यह अपडेट की अनंत श्रृंखला को जन्म दे सकता है। इसे ठीक करने के लिए, उपयोग हुक के दूसरे तर्क के रूप में [] पास करें। (रिएक्शन-हुक /[]useEffect
एग्जॉस्ट

9

तुम भी उपयोग करने के बजाय तत्व पर refs का उपयोग करना चाहते हैं document.getElementById, यह सिर्फ एक और अधिक मजबूत बात है।


@doublejosh मूल रूप से आप सही हैं लेकिन क्या करें यदि आपको उदाहरण के लिए मिक्सअप करने की आवश्यकता है angularJsऔर reactएक से दूसरे में पलायन करते समय? ऐसे मामले हैं जहां एक सीधा डोम हेरफेर वास्तव में आवश्यक है
मेसर्बिल

2

मेरा 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>
    )
}

यहाँ (WidgetHead) क्या याद आ रही है के लिए अपनी कल्पना का उपयोग करते हैं, reactstrapकुछ आप NPM पर मिल सकती है: की जगह innerRefके साथ refएक विरासत डोम तत्व के लिए (एक का कहना है कि<div> )।

का प्रयोग करें या उपयोग करें

अंतिम को परिवर्तनों के लिए समकालिक कहा जाता है

useLayoutEffect (या useEffect ) दूसरा तर्क

दूसरा तर्क एक सरणी है, और पहले तर्क में फ़ंक्शन को निष्पादित करने से पहले इसकी जांच की जाती है।

मैंनें इस्तेमाल किया

[अपने आप को समवर्ती, अपने आप को। वर्तमान में? अपने आप को समवर्ती। क्लियरहाइट: 0]

क्योंकि रेंडर करने से पहले अपने आप को myself.current.clientHeight है जो मैं परिवर्तनों के लिए जांचना चाहता हूं।

मैं यहाँ क्या हल कर रहा हूँ (या हल करने की कोशिश कर रहा हूँ)

मैं एक ग्रिड पर विजेट की समस्या को हल कर रहा हूं जो अपनी इच्छा से अपनी ऊंचाई बदलते हैं, और ग्रिड सिस्टम को प्रतिक्रिया के लिए पर्याप्त लोचदार होना चाहिए ( https://github.com/STRML/react-grid-layout )।


1
महान जवाब, लेकिन सरल उदाहरण से लाभ होगा। मूल रूप से व्हाइटकनाइट का उत्तर लेकिन useLayoutEffectरेफरी को टाई करने के लिए वास्तविक और वास्तविक डिव के साथ ।
बॉट १

1

हुक के साथ प्रयोग:

यदि आपकी सामग्री आयाम लोड होने के बाद बदल जाती है तो यह उत्तर मददगार होगा।

onreadystatechange : तब होता है जब किसी तत्व या HTML दस्तावेज़ से संबंधित डेटा की लोड स्थिति बदल जाती है। जब पृष्ठ की सामग्री की लोड स्थिति बदल गई है, तो onreadystatechange घटना को HTML दस्तावेज़ पर निकाल दिया जाता है।

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

मैं एक youtube वीडियो प्लेयर के साथ काम करने की कोशिश कर रहा था, जिसके आयाम लोड होने के बाद बदल सकते हैं।


0

मुझे उपयोगी npm पैकेज https://www.npmjs.com/package/element-resize-detector मिला

तत्वों के लिए एक अनुकूलित क्रॉस-ब्राउज़र श्रोता का आकार बदलता है।

प्रतिक्रिया घटक या कार्यात्मक घटक के साथ इसका उपयोग कर सकते हैं (प्रतिक्रिया हुक के लिए विशेष रूप से उपयोगी)


0

यहाँ एक और है अगर आपको विंडो आकार परिवर्तन की आवश्यकता है:

class DivSize extends React.Component {

  constructor(props) {
    super(props)

    this.state = {
      width: 0,
      height: 0
    }
    this.resizeHandler = this.resizeHandler.bind(this);
  }

  resizeHandler() {
    const width = this.divElement.clientWidth;
    const height = this.divElement.clientHeight;
    this.setState({ width, height });
  }

  componentDidMount() {
    this.resizeHandler();
    window.addEventListener('resize', this.resizeHandler);
  }

  componentWillUnmount(){
    window.removeEventListener('resize', this.resizeHandler);
  }

  render() {
    return (
      <div 
        className="test"
        ref={ (divElement) => { this.divElement = divElement } }
      >
        Size: widht: <b>{this.state.width}px</b>, height: <b>{this.state.height}px</b>
      </div>
    )
  }
}

ReactDOM.render(<DivSize />, document.querySelector('#container'))

कोड पेन


0

वैकल्पिक समाधान, यदि आप प्रतिक्रियाशील तत्व के आकार को समान रूप से प्राप्त करना चाहते हैं, तो तत्व को दृष्टिगत रूप से प्रस्तुत किए बिना, आप ReactDOMServer और DOMParser का उपयोग कर सकते हैं ।

मैं इस फ़ंक्शन का उपयोग किसी फिक्स्ड-लिस्ट के लिए आवश्यक प्रोप को हार्डकोड करने के बजाय रिएक्शन-विंडो ( प्रतिक्रिया-वर्चुअलाइज्ड ) का उपयोग करते हुए अपनी सूची आइटम रेंडरर की ऊंचाई पाने के itemSizeलिए करता हूं

utilities.js:

/**
 * @description Common and reusable functions 
 * 
 * @requires react-dom/server
 * 
 * @public
 * @module
 * 
 */
import ReactDOMServer from "react-dom/server";

/**
 * @description Retrieve the width and/or heigh of a React element without rendering and committing the element to the DOM.
 * 
 * @param {object} elementJSX - The target React element written in JSX.
 * @return {object} 
 * @public
 * @function
 * 
 * @example
 * 
 * const { width, height } = getReactElementSize( <div style={{ width: "20px", height: "40px" }} ...props /> );
 * console.log(`W: ${width}, H: ${height});  // W: 20, H: 40
 * 
 */
const getReactElementSize = (elementJSX) => {

    const elementString = ReactDOMServer.renderToStaticMarkup(elementJSX);
    const elementDocument = new DOMParser().parseFromString(elementString, "text/html");
    const elementNode = elementDocument.getRootNode().body.firstChild;

    const container = document.createElement("div");
    const containerStyle = {

        display: "block",
        position: "absolute",
        boxSizing: "border-box",
        margin: "0",
        padding: "0",
        visibility: "hidden"
    };

    Object.assign(container.style, containerStyle);

    container.appendChild(elementNode);
    document.body.appendChild(container);

    const width = container.clientWidth;
    const height = container.clientHeight;

    container.removeChild(elementNode);
    document.body.removeChild(container);

    return {

        width,
        height
    };
};

/**
 * Export module
 * 
 */
export {

    getReactElementSize
};
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.