렌더링 전에 리액트 컴포넌트의 크기(높이/폭)를 확인하는 방법
스스로 렌더링하기 전에 치수를 미리 알아야 하는 반응 컴포넌트가 있습니다.
는 jquery로 만들 수 .$('#container').width()
컴포넌트를 만들 때 컨테이너의 폭을 미리 파악합니다.
<div id='container'></div>
이 용기의 치수는 페이지의 다른 용기와 함께 CSS에 정의됩니다.React에서 구성 요소의 높이, 폭 및 배치를 정의하는 사람은 누구입니까?나는 CSS가 그것을 하고 그것에 접근할 수 있는 것에 익숙하다.그러나 React에서는 컴포넌트가 렌더링된 후에만 해당 정보에 액세스할 수 있는 것 같습니다.
다음 예제에서는 react hook useEffect를 사용합니다.
여기서의 작업 예
import React, { useRef, useLayoutEffect, useState } from "react";
const ComponentWithDimensions = props => {
const targetRef = useRef();
const [dimensions, setDimensions] = useState({ width:0, height: 0 });
useLayoutEffect(() => {
if (targetRef.current) {
setDimensions({
width: targetRef.current.offsetWidth,
height: targetRef.current.offsetHeight
});
}
}, []);
return (
<div ref={targetRef}>
<p>{dimensions.width}</p>
<p>{dimensions.height}</p>
</div>
);
};
export default ComponentWithDimensions;
몇 가지 주의사항
useEffect는 폭과 높이에 대한 자신의 영향을 검출할 수 없습니다.
하지 않고 를 들어, 「」는 다음과 같습니다.const [dimensions, setDimensions] = useState({});
시 됩니다.
- css를 통해 컴포넌트에 명시적인 높이가 설정되지 않았습니다.
- useEffect를 사용하여 너비와 높이를 측정할 수 있는 것은 useEffect를 사용할 수 있습니다.
- 구성 요소 내용은 높이 및 너비 변수가 있는 p 태그뿐입니다. 비어 있으면 구성 요소의 높이가 0이 됩니다.
- 새 상태 변수를 설정한 후 useEffect가 다시 실행되지 않습니다.
이것은 대부분의 사용 사례에서는 문제가 되지 않지만, 창 크기 조정에 영향을 미치기 때문에 포함하려고 합니다.
창 크기 조정
나는 또한 원래의 질문에는 탐구되지 않은 몇 가지 함의가 있다고 생각한다.차트 등 동적으로 그려진 컴포넌트의 윈도우 크기 조정 문제에 부딪혔습니다.
이 답변은 명기되어 있지 않지만 기재되어 있습니다.
- 응용 프로그램에서 치수가 필요한 경우 창 크기 조정 시 필요할 수 있습니다.
- 상태 또는 소품 변경만 다시 그릴 수 있으므로 치수 변경을 모니터링하려면 창 크기 조정 청취자도 필요합니다.
- 보다 복잡한 컴포넌트로 창 크기 조정 이벤트마다 컴포넌트를 다시 그리면 퍼포먼스가 향상됩니다.set Timeout과 clear를 도입했습니다.인터벌은 도움이 되었다.내 컴포넌트에 차트가 포함되어 있어서 CPU가 급증하고 브라우저가 크롤링하기 시작했다.아래 해결방법으로 이것을 수정했습니다.
아래의 코드, 여기서의 작업 예
import React, { useRef, useLayoutEffect, useState } from 'react';
const ComponentWithDimensions = (props) => {
const targetRef = useRef();
const [dimensions, setDimensions] = useState({});
// holds the timer for setTimeout and clearInterval
let movement_timer = null;
// the number of ms the window size must stay the same size before the
// dimension state variable is reset
const RESET_TIMEOUT = 100;
const test_dimensions = () => {
// For some reason targetRef.current.getBoundingClientRect was not available
// I found this worked for me, but unfortunately I can't find the
// documentation to explain this experience
if (targetRef.current) {
setDimensions({
width: targetRef.current.offsetWidth,
height: targetRef.current.offsetHeight
});
}
}
// This sets the dimensions on the first render
useLayoutEffect(() => {
test_dimensions();
}, []);
// every time the window is resized, the timer is cleared and set again
// the net effect is the component will only reset after the window size
// is at rest for the duration set in RESET_TIMEOUT. This prevents rapid
// redrawing of the component for more complex components such as charts
window.addEventListener('resize', ()=>{
clearInterval(movement_timer);
movement_timer = setTimeout(test_dimensions, RESET_TIMEOUT);
});
return (
<div ref={ targetRef }>
<p>{ dimensions.width }</p>
<p>{ dimensions.height }</p>
</div>
);
}
export default ComponentWithDimensions;
re: 창 크기 조정 타임아웃 - 이 값에서 다운스트림 차트를 사용하여 대시보드를 그리는데 100ms가RESET_TIMEOUT
CPU 사용량과 응답성 사이에서 균형을 잘 잡은 것 같습니다.저는 어떤 것이 이상적인지에 대한 객관적인 데이터가 없기 때문에 이것을 변수로 삼았습니다.
이미 언급했듯이 DOM에 렌더링될 때까지 요소의 치수를 가져올 수 없습니다.할 수 하고 React에서 크기를입니다.componentDidMount
이치노
나는 모범을 보였다.
은 이쪽에서 사용한다는 점에 유의하시기 바랍니다.setState
componentDidMount
안티 패턴이지만, 이 경우는 문제가 없습니다.그것이 바로 우리가 달성하려고 하는 것이기 때문입니다.
건배!
코드:
import React, { Component } from 'react';
export default class Example extends Component {
state = {
dimensions: null,
};
componentDidMount() {
this.setState({
dimensions: {
width: this.container.offsetWidth,
height: this.container.offsetHeight,
},
});
}
renderContent() {
const { dimensions } = this.state;
return (
<div>
width: {dimensions.width}
<br />
height: {dimensions.height}
</div>
);
}
render() {
const { dimensions } = this.state;
return (
<div className="Hello" ref={el => (this.container = el)}>
{dimensions && this.renderContent()}
</div>
);
}
}
할 수 없어요.어쨌든 믿을 수 있는 건 아니야.이것은 브라우저 동작의 일반적인 제한이며, React가 아닙니다.
했을 때$('#container').width()
DOM에 렌더링된 요소의 너비를 조회하고 있습니다.jQuery에서도 이 문제를 피할 수 없습니다.
요소를 렌더링하기 전에 반드시 요소의 폭이 필요한 경우 요소를 추정해야 합니다.표시하기 전에 측정해야 하는 경우 적용하면서 측정하면 됩니다.visibility: hidden
또는 페이지 상의 어딘가로 이산적으로 렌더링한 후 측정 후 이동합니다.
창 크기 조정에 대한 @shane의 접근법에 예기치 않은 "gotcha"가 있습니다.기능 컴포넌트는 모든 리렌더에 새로운 이벤트청취자를 추가하며 이벤트청취자를 삭제하지 않으므로 이벤트청취자의 수는 크기 조정마다 기하급수적으로 증가합니다.각 콜을 window.addEventListener에 기록함으로써 확인할 수 있습니다.
window.addEventListener("resize", () => {
console.log(`Resize: ${dimensions.width} x ${dimensions.height}`);
clearInterval(movement_timer);
movement_timer = setTimeout(test_dimensions, RESET_TIMEOUT);
});
이 문제는 이벤트 정리 패턴을 사용하여 해결할 수 있습니다.다음은 @shane의 코드와 이 튜토리얼이 혼합된 코드이며, 커스텀 훅에 크기 조정 로직이 포함되어 있습니다.
/* eslint-disable react-hooks/exhaustive-deps */
import React, { useState, useEffect, useLayoutEffect, useRef } from "react";
// Usage
function App() {
const targetRef = useRef();
const size = useDimensions(targetRef);
return (
<div ref={targetRef}>
<p>{size.width}</p>
<p>{size.height}</p>
</div>
);
}
// Hook
function useDimensions(targetRef) {
const getDimensions = () => {
return {
width: targetRef.current ? targetRef.current.offsetWidth : 0,
height: targetRef.current ? targetRef.current.offsetHeight : 0
};
};
const [dimensions, setDimensions] = useState(getDimensions);
const handleResize = () => {
setDimensions(getDimensions());
};
useEffect(() => {
window.addEventListener("resize", handleResize);
return () => window.removeEventListener("resize", handleResize);
}, []);
useLayoutEffect(() => {
handleResize();
}, []);
return dimensions;
}
export default App;
여기 작업 예가 있습니다.
이 코드는 단순성을 위해 타이머를 사용하지 않지만 링크된 튜토리얼에서 이 접근법에 대해 설명합니다.
앞에서 설명한 바와 같이 브라우저의 제한은 DOM을 조작하는 스크립트 간 및 이벤트 핸들러 실행 간에 한 번에 "한 스레드 내" 렌더링하는 것입니다.DOM을 조작/로드한 후 치수를 얻으려면 양보(함수에서 탈퇴)하고 브라우저에 렌더링을 맡기고 렌더링이 완료된 이벤트에 반응해야 합니다.
하지만 다음 방법을 시도해 보세요.
CSS를 설정할 수 있습니다.display: hidden; position: absolute;
원하는 폭을 얻기 위해 보이지 않는 경계 상자로 제한합니다.다음으로 렌더링 완료 후 콜을 실시합니다.$('#container').width()
.
아이디어는 다음과 같습니다.display: hidden
요소가 표시되는 경우 필요한 공간을 차지하도록 합니다.연산은 백그라운드에서 수행해야 합니다.나는 그것이 "렌더하기 전"으로 적합하다고 확신할 수 없다.
면책사항:
아직 안 해봤으니까 잘 됐는지 알려주세요.
그리고 리액트랑 어떻게 섞일지 모르겠어요.
@Stanko의 솔루션은 훌륭하고 간결하지만, 렌터 후의 것입니다.다른 시나리오가 있는데<p>
SVG 내의 요소<foreignObject>
(리차트 차트에서).그<p>
줄바꿈 텍스트와 너비 구속의 최종 높이를 포함합니다.<p>
예측하기 어렵다.그<foreignObject>
뷰포트는 기본적으로 뷰포트로 너무 길면 기본 SVG 요소에 대한 클릭/탭을 차단하고 너무 짧아서 아래쪽을 잘라냅니다.<p>
리액트 렌더링 전에 DOM만의 스타일로 정해진 높이가 필요합니다.그리고 JQuery는 없습니다.
기능하는 React 컴포넌트에서 더미를 만듭니다.<p>
노드를 문서의 클라이언트 뷰포트 외부에 있는 실시간 DOM에 배치하고 측정한 후 다시 제거합니다.그런 다음 이 측정을 사용하여<foreignObject>
.
[CSS 수업을 이용한 방법으로 편집][편집:파이어폭스는 findCssClassBy를 싫어한다.셀렉터, 지금은 하드코딩으로 고정되어 있습니다.]
const findCssClassBySelector = selector => [...document.styleSheets].reduce((el, f) => {
const peg = [...f.cssRules].find(ff => ff.selectorText === selector);
if(peg) return peg; else return el;
}, null);
// find the class
const eventLabelStyle = findCssClassBySelector("p.event-label")
// get the width as a number, default 120
const eventLabelWidth = eventLabelStyle && eventLabelStyle.style ? parseInt(eventLabelStyle.style.width) : 120
const ALabel = props => {
const {value, backgroundcolor: backgroundColor, bordercolor: borderColor, viewBox: {x, y}} = props
// create a test DOM node, place it out of sight and measure its height
const p = document.createElement("p");
p.innerText = value;
p.className = "event-label";
// out of sight
p.style.position = "absolute";
p.style.top = "-1000px";
// // place, measure, remove
document.body.appendChild(p);
const {offsetHeight: calcHeight} = p; // <<<< the prize
// does the DOM reference to p die in garbage collection, or with local scope? :p
document.body.removeChild(p);
return <foreignObject {...props} x={x - eventLabelWidth / 2} y={y} style={{textAlign: "center"}} width={eventLabelWidth} height={calcHeight} className="event-label-wrapper">
<p xmlns="http://www.w3.org/1999/xhtml"
className="event-label"
style={{
color: adjustedTextColor(backgroundColor, 125),
backgroundColor,
borderColor,
}}
>
{value}
</p>
</foreignObject>
}
추악하고, 많은 추측들이 있고, 아마 느리고, 쓰레기 때문에 불안하지만, 효과가 있어요.폭 받침은 숫자여야 합니다.
스택 오버플로에서 찾은 모든 솔루션은 매우 느리거나 최신 React 규약에 맞지 않습니다.그러다가 우연히 발견했어
https://github.com/wellyshen/react-cool-dimensions
ResizeObserver를 사용하여 요소의 크기를 측정하고 응답성 구성 요소를 고성능으로 처리하는 React 후크입니다.
여기서 시도한 솔루션보다 훨씬 빠르고 동작도 좋습니다.
import { useState, useEffect } from 'react'
const useContainerDimensions = containerRef => {
const getDimensions = () => ({
width: containerRef.current.offsetWidth,
height: containerRef.current.offsetHeight
})
const [dimensions, setDimensions] = useState({ width: 0, height: 0 })
useEffect(() => {
const handleResize = () => {
setDimensions(getDimensions())
}
let dimensionsTimeout = setTimeout(() => {
if(containerRef.current) {
setDimensions(getDimensions())
}
}, 100)
window.addEventListener("resize", handleResize)
return () => {
clearTimeout(dimensionsTimeout)
window.removeEventListener("resize", handleResize)
}
}, [containerRef])
return dimensions
}
export default useContainerDimensions
useContainerDimensions 사용자 지정 후크를 사용할 수 있습니다.픽셀의 폭과 높이가 필요한 경우 clientWidth와 client를 사용할 수 있습니다.오프셋 너비 및 오프셋 대신 높이높이.
언급URL : https://stackoverflow.com/questions/49058890/how-to-get-a-react-components-size-height-width-before-render
'source' 카테고리의 다른 글
.htaccess 내부 리다이렉트가 문자열 매개 변수와 함께 작동하지 않음 (0) | 2023.02.14 |
---|---|
clearity.js by Microsoft에 의한 전체적인 페이지 로드 속도 저하 (0) | 2023.02.14 |
wordpress의 함수에 대한 인수 2가 누락되었습니다. (0) | 2023.02.14 |
웹 팩 로더와 플러그인의 차이점 (0) | 2023.02.14 |
ORA-01810: 포맷 코드가 2회 표시됨 (0) | 2023.02.14 |