score:37
see this fiddle (actually updated your's)
you need to hook into componentdidmount
which is run after render method. there, you get actual height of element.
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>
score:0
i found useful npm package https://www.npmjs.com/package/element-resize-detector
an optimized cross-browser resize listener for elements.
can use it with react component or functional component(specially useful for react hooks)
score:0
here's a nice reusable hook amended from 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];
}
to implement:
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>
);
};
score:1
an alternative solution, in case you want to retrieve the size of a react element synchronously without having to visibly render the element, you can use reactdomserver and domparser.
i use this function to get the height of a my list item renderer when using react-window (react-virtualized) instead of having to hardcode the required itemsize
prop for a fixedsizelist.
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
};
score:1
i found the other answers with react hooks were not updating properly upon resize.
after searching around i found this blog post that gives a working react hook that observes resize events:
the tl;dr is here:
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;
then an example usage in a component:
// 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;
score:1
you can also use getboundingclientrect()
to get height, width.
const [width, setwidth] = usestate(0);
useeffect(() => {
const element = document.getelementbyid('element-id');
if (element) {
setwidth(element.getboundingclientrect().width); // or height
}
}, []);
score:2
here is another one if you need window resize event:
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'))
score:2
use the usemeasure
as custom hook (typescript, ssr, hook):
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;
score:5
using with hooks :
this answer would be helpful if your content dimension changes after loading.
onreadystatechange : occurs when the load state of the data that belongs to an element or a html document changes. the onreadystatechange event is fired on a html document when the load state of the page's content has changed.
import {usestate, useeffect, useref} from 'react';
const ref = useref();
useeffect(() => {
document.onreadystatechange = () => {
console.log(ref.current.clientheight);
};
}, []);
i was trying to work with a youtube video player embedding whose dimensions may change after loading.
score:8
my 2020's (or 2019) answer
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>
)
}
let use your imagination for what is missing here (widgethead), reactstrap
is something you can find on npm: replace innerref
with ref
for a legacy dom element (say a <div>
).
useeffect or uselayouteffect
the last is said to be synchronous for changes
uselayouteffect
(or useeffect
) second argument
second argument is an array, and it is checked before executing the function in the first argument.
i used
[myself.current, myself.current?myself.current.clientheight:0]
because myself.current is null before rendering, and that is a good thing not to check, the second parameter at the end myself.current.clientheight
is what i want to check for changes.
what i am solving here (or trying to solve)
i am solving here the problem of widget on a grid that change its height by their own will, and the grid system should be elastic enough to react ( https://github.com/strml/react-grid-layout ).
score:9
it might show zero. settimeout helps to get the correct value and update the state.
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>
)
}
score:12
you would also want to use refs on the element instead of using document.getelementbyid
, it's just a slightly more robust thing.
score:28
instead of using document.getelementbyid(...)
, a better (up to date) solution is to use the react useref hook that stores a reference to the component/element, combined with a useeffect hook, which fires at component renders.
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>
)
}
score:187
for those who are interested in using react hooks
, this might help you get started.
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>
)
}
score:192
following is an up to date es6 example using a ref.
remember that we have to use a react class component since we need to access the lifecycle method componentdidmount()
because we can only determine the height of an element after it is rendered in the 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'))
you can find the running example here: https://codepen.io/bassgang/pen/povzjkw
Source: stackoverflow.com
Related Query
- ReactJS - Get Height of an element
- How to get div or element height in ReactJS
- Get viewport/window height in ReactJS
- ReactJS get rendered component height
- how to get element by component name in ReactJS
- Reactjs - Get Height of a div/image using React Hooks
- How to get the ReactJS element inside componentDidMount()?
- Get the height of an children element
- Get clicked ID from parent to child element with ReactJs
- ReactJS get ref to child element and setting its scrollTop position
- How can i get an input element from a component in reactjs
- How to get element properties in reactjs
- How to get an element height in react js with out using any pulgin
- Get font color of ReactJS element
- reactjs get the children count of an element
- How to get DOM element properties before they render in ReactJS
- How do I get the exact height of an element which the height css attribute is set auto in reactjs?
- React get native element or Height and Width of a child that was passed in props
- How to get element height and width from ReactNode?
- React: How to get the ref height of an element coming from the children with dynamic height?
- Get height from this.props.children in ReactJS
- Can't get real element height in React
- Reactjs how to get value from selected element
- How to get the new child element reactjs
- Get height of element when useState is initially set
- How to get Element using useRef in ReactJS
- ReactJS - Adding an Input field with each element and get value from it
- How to get DOM element id with OnClick inside map fuction in ReactJs
- How to get height of an element at each page update
- ReactJS get image from the element above
More Query from same tag
- Is there a way to prevent redirection after form submission and still send the form data to the server?
- How to sort nested object in an array?
- Buttons toggle in React
- React setState won't update
- How to get SCSS variables into react
- How do I get my react app to display object information in my bootstrap modal when they click on a list item?
- Show fetch results in render return() in React.js
- 'props' of undefined inside map closure
- Why is a statically generated page unstyled when sent to the client?
- GET http://localhost:5000/auth/me 404 (Not Found)
- In what condition it will re-render while using react custom hooks
- How do I unsubscribe to the dispatch to grab new data onload on useEffect? - I'm using Redux Toolkit
- .tsx component Button onclick event shows undefined
- How to merge two methods for react and google realtime database?
- react-router-dom v6 rendering new page over current page
- How to avoid duplicate event listener in react?
- Decimal format number React
- select all checkBox funcationality in react-redux
- Update component state on route-change? (react-router)
- Dynamically change class based on current index in a react component. (object.map)
- Using fetch in a custom React hook - data is fetching twice
- Dynamic Rendering vs Hybrid Rendering
- Can't align table properly
- MUI: The `value` provided to the Tabs component is invalid. The Tab with this `value` ("0") is not part of the document layout
- Uncaught TypeError: event.preventDefault is not a function (react.js)
- basic React Gatsby project - can't push to GitHub - getting "git push --set-upstream origin master"
- Extending typescript interfaces
- Make MUI dialog content size follow the size of the content
- React looping hooks to display in other hook
- How can i get useState to update immediately