I have a react app that is purely built with functional components. I want to get the height of an element after it has been rendered on screen to change size of it's parent accordingly.
There are solutions for class based apps but I couldn't find any for functional components.
i tried this solution from answers but it is not running the useEffect hook
here is extracted code from my component
import React, {useRef, useEffect} from 'react';
import {
MenuContainer,
GrayBox,
Wrapper
} from '../LayersMenu/LayerMenu.styles';
export const Component = ({ category, showStatistics }) => {
const grayBoxRef= useRef(null);
const wrapperRef= useRef(null);
const testRef= useRef(null);
useEffect(()=>{
const height = wrapperRef.current.offsetHeight;
console.log(height,'check');
}, [wrapperRef])
useEffect(()=>{
const height = testRef.current.offsetHeight;
console.log(height,'check2');
},[testRef]);
return (
<MenuContainer ref={testRef}>
<GrayBox ref={grayBoxRef}>
<Wrapper ref={wrapperRef} hasAnyAllowedStats={showStatistics}>
</Wrapper>
</GrayBox>
</MenuContainer>
);
};
PS: accepted answer didn't work for my answer but it works for the project he added in answer works so i guess there is something wrong with my project structure or something not entirely sure.
Thanks alot for answer
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With