IT이야기

반응JS - 요소의 높이 가져오기

cyworld 2022. 4. 9. 09:12
반응형

반응JS - 요소의 높이 가져오기

반응에서 해당 요소를 렌더링한 후 요소의 높이를 얻는 방법은?

HTML

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

리액션JS

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여야 한다.지스피들

다음은 참조를 사용한 최신 ES6 예다.

Lifecycle 메소드에 액세스해야 하므로 React 클래스 구성 요소를 사용해야 함을 기억하십시오.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에서 확인할 수 있다.

이용에 관심이 있는 분들을 위해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>
  )
}

바이올린 보기(실제 업데이트)

에 연결해야 한다.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>

사용하는 대신document.getElementById(...)보다 나은(최신) 솔루션은 구성요소/요소에 대한 참조를 저장하는 React useRef 후크를 useEffect 후크와 조합하여 구성요소 렌더에 발포하는 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>
  )
}

또한 요소를 사용하는 대신 요소에 대한 참조를 사용하려는 경우document.getElementById조금 더 강한 것일 뿐이지

0으로 나타날 수 있다. 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>
      )
    }

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

여기에 없는 것에 당신의 상상력을 사용하자 (위젯헤드)reactstrapnpm에서 찾을 수 있는 것: 교체innerRef와 함께ref레거시 돔 요소에 대해 (A라고 말한다.)<div>).

useEffect 또는 useLayoutEffect

마지막은 변화를 위해 동기화된다고 한다.

useLayoutEffect(또는)useEffect) 두 번째 인수

두 번째 인수는 배열이며, 첫 번째 인수의 함수를 실행하기 전에 확인된다.

나는 사용했다.

[reason.current, myself.current?current.cur높이:0]

왜냐하면 렌더링하기 전에 myself.current가 null이기 때문에 끝의 두 번째 파라미터는 확인하지 않는 것이 좋기 때문이다.myself.current.clientHeight변화를 확인하고 싶은 거야

여기서 해결하는 것(또는 해결하려는 것)

나는 여기서 그들의 의지에 의해 그것의 높이를 바꾸는 그리드 상의 위젯의 문제를 해결하고 있으며, 그리드 시스템은 반응할 수 있을 만큼 충분히 탄력적이어야 한다(https://github.com/STRML/react-grid-layout).

후크와 함께 사용:

이 답변은 로딩 후 콘텐츠 차원이 변경될 경우 도움이 될 수 있다.

onreadystatechange : 요소나 HTML 문서에 속하는 데이터의 로드 상태가 변경될 때 발생한다.페이지 내용의 로드 상태가 변경되면 HTML 문서에서 onreadystatechange 이벤트가 실행된다.

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

로드 후 치수가 바뀔 수 있는 유튜브 비디오 플레이어를 삽입하여 작업하려고 했다.

창 크기 조정 이벤트가 필요한 경우 다음 항목을 참조하십시오.

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

암호펜

대체 솔루션으로, 요소를 눈에 띄게 렌더링할 필요 없이 동시에 리액션 요소의 크기를 검색하려는 경우 리액션DOMServerDOMParser를 사용할 수 있다.

이 기능을 사용하여 필요한 하드코드를 사용하지 않고 리액션 윈도우(react-virtualized)를 사용할 때 목록 항목 렌더러의 높이를 얻음itemSizeFixedSizeList용 받침대

공공 시설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
};

나는 크기 조정 시 반응 후크가 올바르게 업데이트되지 않는 다른 답변을 발견했다.

검색한 후 이벤트 크기 조정 관찰을 위한 리액션 후크를 제공하는 블로그 게시물을 찾았다.

TL;DR은 다음과 같다.

npm install --save resize-observer-polyfill

// useResizeObserver.js
import { useEffect, useRef } from 'react';
import PropTypes from 'prop-types';
import ResizeObserver from 'resize-observer-polyfill';

const useObserver = ({ callback, element }) => {

  const current = element && element.current;

  const observer = useRef(null);

  useEffect(() => {
      // if we are already observing old element
      if (observer && observer.current && current) {
        observer.current.unobserve(current);
      }
      const resizeObserverOrPolyfill =  ResizeObserver;
      observer.current = new resizeObserverOrPolyfill(callback);
      observe();

      return () => {
        if (observer && observer.current && element &&
           element.current) {
          observer.current.unobserve(element.current);
        }
      };
  }, [current]);

  const observe = () => {
    if (element && element.current && observer.current) {
      observer.current.observe(element.current);
    }
  };

};

useObserver.propTypes = {
  element: PropTypes.object,
  callback: PropTypes.func,
};

export default useObserver;

그런 다음 구성 요소의 사용 예:

// shape.js
import React, { useEffect, useState, useRef } from 'react';
import useResizeObserver from 'path/to/useResizeObserver.js';

const Shape = () => {
  const [height, setHeight] = useState(0);
  const svgRef = useRef(null);

  const doHeightAdjustment = () => {
    setHeight(svgRef.current.clientHeight);
  };

  useResizeObserver({callback: doHeightAdjustment, element: svgRef});

  return (
    <div ref={svgRef} style={{ height: '100vh' }}>
      {height}
    </div>
  );
};

export default Shape;

당신은 또한 사용할 수 있다.getBoundingClientRect()키, 너비를 얻기 위해서.

const [width, setWidth] = useState(0);

useEffect(() => {
    const element = document.getElementById('element-id');
    if (element) {
      setWidth(element.getBoundingClientRect().width); // or height
    }
  }, []);

사용useMeasure사용자 정의 후크(형식, SSR, 후크):

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

interface ContainerSize {
  width: number;
  height: number;
}

type UseMeasureArgs = () => {
  ref: React.RefObject<HTMLDivElement>;
  size: ContainerSize;
  windowSize: ContainerSize;
};

const initSize: ContainerSize = { width: 0, height: 0 };

const useMeasure: UseMeasureArgs = () => {
  const ref = useRef<HTMLDivElement>(null);
  const [size, setSize] = useState<ContainerSize>(initSize);
  const [windowSize, setWindowSize] = useState<ContainerSize>(initSize);

  useEffect(() => {
    if (ref.current) {
      setSize({ width: ref.current.offsetWidth, height: ref.current.offsetHeight });
    }
    if (typeof window !== 'undefined') {
      setWindowSize({
        width: window.innerWidth,
        height: window.innerHeight,
      });
    }
  }, []);

  return { ref, size, windowSize };
};

export default useMeasure;

유용한 npm 패키지 https://www.npmjs.com/package/element-resize-detector을 찾았다.

최적화된 크로스 브라우저로 요소의 수신기 크기 조정.

반응 구성 요소 또는 기능 구성 요소와 함께 사용할 수 있음(반응 후크에 특히 유용함

여기 https://swizec.com/blog/usedimensions-a-react-hook-to-measure-dom-nodes에서 수정한 재사용 가능한 멋진 훅이 있다.

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

function getDimensionObject(node) {
  const rect = node.getBoundingClientRect();

  return {
    width: rect.width,
    height: rect.height,
    top: 'x' in rect ? rect.x : rect.top,
    left: 'y' in rect ? rect.y : rect.left,
    x: 'x' in rect ? rect.x : rect.left,
    y: 'y' in rect ? rect.y : rect.top,
    right: rect.right,
    bottom: rect.bottom
  };
}

export function useDimensions(data = null, liveMeasure = true) {
  const [dimensions, setDimensions] = useState({});
  const [node, setNode] = useState(null);

  const ref = useCallback(node => {
    setNode(node);
  }, []);

  useEffect(() => {
    if (node) {
      const measure = () =>
        window.requestAnimationFrame(() =>
          setDimensions(getDimensionObject(node))
        );
      measure();

      if (liveMeasure) {
        window.addEventListener('resize', measure);
        window.addEventListener('scroll', measure);

        return () => {
          window.removeEventListener('resize', measure);
          window.removeEventListener('scroll', measure);
        };
      }
    }
  }, [node, data]);

  return [ref, dimensions, node];
}

구현 방법:

import { useDimensions } from '../hooks';

// Include data if you want updated dimensions based on a change.
const MyComponent = ({ data }) => {
  const [
    ref,
    { height, width, top, left, x, y, right, bottom }
  ] = useDimensions(data);

  console.log({ height, width, top, left, x, y, right, bottom });

  return (
    <div ref={ref}>
      {data.map(d => (
        <h2>{d.title}</h2>
      ))}
    </div>
  );
};

참조URL: https://stackoverflow.com/questions/35153599/reactjs-get-height-of-an-element

반응형