1

Let's say I have a component that takes an element as a prop called customHeader:

const Example = ({ children, customHeader }) => {
  ...some code  

  return (
    <>
      {customHeader ? customHeader : <div>Default Header</div>}
      {children}
    </>
  );
}

Then where I use the Example component I do the following:

<Example customHeader={<div>blah</div>}>
  <div>children</div>
</Example>

So far this is fairly standard stuff and everything is working but the problem I have is that I want to be able to grab the dimensions of the customHeader element by doing something like customHeader.clientHeight but that won't work. When I console.log it I get this object printed out:

{
  $$typeof: Symbol(react.element)
  key: ".0"
  props: {children: 'Blah'}
  ref: null
  type: "div"
  _owner: FiberNode {tag: 0, key: null, stateNode: null, elementType: ƒ, type: ƒ, …}
  _store: {validated: false}
}

Is there a way to convert a JSX element that is passed as a prop to an "normal" HTML element so I can read a bunch of information off it?

Avi
  • 1,049
  • 1
  • 5
  • 16
  • 3
    You'll need to use a ref to get info about the dom element. – 0stone0 Mar 16 '23 at 14:02
  • 1
    `customHeader` will be a react element, not a dom element. – evolutionxbox Mar 16 '23 at 14:04
  • 1
    Does this answer your question? [How to access a DOM element in React? What is the equilvalent of document.getElementById() in React](https://stackoverflow.com/questions/38093760/how-to-access-a-dom-element-in-react-what-is-the-equilvalent-of-document-getele) – evolutionxbox Mar 16 '23 at 14:04

1 Answers1

5

You could use cloneElement to assign an useRef to the component that will have the aRef.current.clientHeight you're looking for

I've added a simple <button> to add some padding to the customHeader so you can see the clientHeight change it's value

const { useEffect, useRef, useState } = React;

const Example = ({ children, customHeader }) => {
   
    const aRef = useRef();
    
    useEffect(() => {
        if (aRef.current) {
            const clientHeight = aRef.current.clientHeight;
            console.log(`ClientHeight: ${clientHeight}`);
        }
    }, [ customHeader ]);

    return (
        <React.Fragment>
            {children}
            {
                (customHeader) 
                    ? React.cloneElement(customHeader, { ref: aRef }) 
                    : <div>Default Header</div>
            }
        </React.Fragment>
    );
}

const App = () => {

    /* Demo purpose only */
    const [customHeaderPadding, setCustomHeaderPadding] = useState(0);
    const toggleCustomHeaderPadding = () => {
        const newValue = (customHeaderPadding === 0) ? 50 : 0;
        setCustomHeaderPadding(newValue);
    }
    /* Demo purpose only */
      
    return (
        <Example customHeader={<div style={{ padding: customHeaderPadding }}>blah</div>}>
           <button onClick={toggleCustomHeaderPadding}>{'Toggle Padding'}</button>
           <div>children</div>
        </Example>   
    );
}

ReactDOM.render(<App />, document.getElementById("react"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="react"></div>
0stone0
  • 34,288
  • 4
  • 39
  • 64
  • 1
    Yea, you're right, removed the default `[]`. Thanks. – 0stone0 Mar 16 '23 at 14:13
  • 2
    `{ref: aRef}` is sufficient; you don't need to make the ref a function. – Unmitigated Mar 16 '23 at 14:15
  • 2
    [^^](https://stackoverflow.com/questions/75757324/how-to-get-the-dimensions-of-an-element-passed-as-a-prop/75757389#comment133640153_75757423) As Unmitigated said, as used above there's no reason for it to be a callback ref. But you *could* use a callback ref *instead* of the effect callback: https://reactjs.org/docs/hooks-faq.html#how-can-i-measure-a-dom-node – T.J. Crowder Mar 16 '23 at 14:18