Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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

like image 939
Faizan Ul Haq Avatar asked Nov 19 '19 20:11

Faizan Ul Haq


1 Answers

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.

like image 81
norbitrial Avatar answered Oct 27 '22 09:10

norbitrial