How to Get Parent Width/Height in React Using Hooks

React: How to get Parent component's width from Child component with hooks?

in order to access ref in your child component, you need to wrap you component in a React.forwardRef function & use the ref as the second argument & not inside the props object so:

const Child = React.forwardRef((props, ref) => {})

& in your parent you would have:

<Child ref={parentRef}/>

you can read more about it here

How to get a react component's size (height/width) before render?

As it was already mentioned, you can't get any element's dimensions until it is rendered to DOM. What you can do in React is to render only a container element, then get it's size in componentDidMount, and then render rest of the content.

I made a working example.

Please note that using setState in componentDidMount is an anti-pattern but in this case is fine, as it is exactly what are we trying to achieve.

Cheers!

Code:

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

How to measure the height of a child and pass it to a parent in React?

Personally, I would call the hook in the Main component and wrap the child component in a forwardRef (check docs here).

See full example here:

Main.tsx

export default function Main(props: { notifications: Notification[] }) {
const { notifications } = props;
const [ref, dimensions] = useDimensions()

return (
<main>
<Header ref={ref}/>
{JSON.stringify(dimensions)}
</main>
)
}

What's done here, we just pass the ref down the tree to the child component and we just show the dimensions (testing purposes).

DefaultHeader.tsx

import { forwardRef } from "react";

const DefaultHeader = forwardRef((_, ref) => {
return (
<>
<div ref={ref} className="header" >
<h1>Hello!</h1>
</div>
</>
);
});

export default DefaultHeader;

Here, we just attach the ref to the container that it has previously been (your example).

See full example on this CodeSandbox.

Let me know if you need more explanations on this.

React get size of parent element within ResponsiveReactGridLayout

Property 'width' does not exist on type 'never'

This is actually a TypeScript error. It means that TypeScript doesn't know what the type of the .current property is supposed to be. Therefore it doesn't know that .current has properties .width and .height and it prevents you from accessing them. You need to tell TypeScript that this is a ref to a div.

An HTMLDivElement doesn't actually have .width and .height, but you can use .clientWidth or .offsetWidth instead.

const canvasRef = useRef<HTMLDivElement>(null);


I've tried using the useRef() hook, but it always seems to have current as null.

The ResponsiveReactGridLayout component is setting its own refs on its children, so your ref={canvasRef} gets overwritten.

The simplest way around this is to add another layer of nesting. The ResponsiveReactGridLayout will set a ref on the outermost div, but you can add another div inside of it with a ref that you control. Make sure that it fills up the entire height.

Note that the .current property might still be null on the first render. You can use a default value, as suggested by @PushpikaWan, or you can delay rendering the chart until you have an actual width.

<ResponsiveReactGridLayout /*...props...*/ >
<div key="candlestick" className="box">
<div ref={canvasRef} style={{ width: "100%", height: "100%" }}>
{canvasRef.current ? (
<Candlestick
data={data}
width={canvasRef.current.clientWidth}
height={canvasRef.current.offsetHeight}
/>
) : null}
</div>
</div>
/*...other children...*/
</ResponsiveReactGridLayout>

I needed to add an explicit width on the grid layout in order to get this to work. I'm not sure if you are doing this part already, but you can use the WidthProvider as explained in the docs.

import { Responsive, WidthProvider } from 'react-grid-layout';

const ResponsiveReactGridLayout = WidthProvider(Responsive);

CodeSandbox Demo

How to get size of an element in an react app that is totally based on functional components?

Instead of using class component with componentDidMount there is a hook called useEffect which can help you to catch somehow the rendered state of the component.

The solution to get height of a rendered DOM element can be the following with functional component:

 const YourComponent = () => {
const inputRef = useRef(null);
useEffect(() => {
const height = inputRef.current.offsetHeight;
console.log('Input height', height);
}, [inputRef]);

return <>
<input ref={inputRef} type="text" defaultValue="testing" />
</>
}

Explanation:

useRef hook will help you to keep the reference for your object for the life of your component, as the documentation states:

useRef returns a mutable ref object whose .current property is initialized to the passed argument (initialValue). The returned object will persist for the full lifetime of the component.

Once you use useEffect combined with useRef just like in the above solution you will get the expected result. For useEffect hook the documentation explains:

The function passed to useEffect will run after the render is committed to the screen.

Passing inputRef to the dependency array will trigger the passed function on change of the input element for useEffect. Then the code calculates the height of your component which in this case just an input element. This can be any DOM element, just like a div.

UPDATE:

From your updated question, the solution is forwardRef, read in the documentation:

Ref forwarding is a technique for automatically passing a ref through a component to one of its children.

With this technique you can access the child component's properties in the parent component e.g.: height of an internal <div> or <input> element what the code can use for further purposes.

In your child functional component, the code should use forwardRef in order to access internal DOM elements, just like below:

import React, { forwardRef } from 'react';

// ...

const YourComponent = forwardRef((props, ref) => {
return <>
<input ref={ref} type="text" defaultValue="testing" />
</>
});

Then use in the parent component as the following:

const componentRef = useRef(null);
useEffect(() => {
const {offsetHeight} = componentRef.current;
console.log('componentRef height', offsetHeight);
}, [componentRef]);

return <>
<YourComponent ref={componentRef} />
</>

If you are interested further then please find the documentation here:
Forwarding refs to DOM components

Please find a working GitHub solution for your scenario what I just built up for representation:
norbitrial/react-forwarding-ref-example

Hope this gives you the idea to proceed further.

In React, how can I calculate the width of a parent based on it's child components?

Sounds like a use case for ResizeObserver API.

function useResizeObserver() {
const [size, setSize] = useState({ width: 0, height: 0 });
const resizeObserver = useRef(null);

const onResize = useCallback((entries) => {
const { width, height } = entries[0].contentRect;
setSize({ width, height });
}, []);

const ref = useCallback(
(node) => {
if (node !== null) {
if (resizeObserver.current) {
resizeObserver.current.disconnect();
}
resizeObserver.current = new ResizeObserver(onResize);
resizeObserver.current.observe(node);
}
},
[onResize]
);

useEffect(
() => () => {
resizeObserver.current.disconnect();
},
[]
);

return { ref, width: size.width, height: size.height };
}

Edit ResizeObserver Example

ReactJS - Get Height of an element

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>


Related Topics



Leave a reply



Submit