1

I have been searching at lengths for an answer to this question, without success.

I would like to find the size of a React component, from another component. Is there another way to do it than the approaches I have listed below?

I will use the answer to dynamically get the height of my navbar from other components and hooks that need it.

Usecase examples


  1. Hooks that smooth-scroll to certain targets, adjusting for navbar height.
  2. Components that animate children when they are visible in the viewport, and therefore also need to adjust for navbar height.

What I have tried


  1. Attaching a ref to the navbar, then forwarding that around my entire application. That's a bit of a nightmare.
  2. Adding an id to the navbar container, then finding it with vanilla js (getElementById). I understand from many other answers, that this is inferior to using a ref.
evolutionxbox
  • 3,932
  • 6
  • 34
  • 51
Magnus
  • 6,791
  • 8
  • 53
  • 84
  • "forwarding that around my entire application", you could always make use of a [context](https://reactjs.org/docs/context.html) to avoid the mess that passing the ref around causes. – DBS Dec 07 '22 at 17:07
  • You could also have navbar measures its own height and save that value in context instead of the ref itself, if messing with the DOM node is giving you trouble. – cjl750 Dec 07 '22 at 17:15
  • That is very helpful, I had forgotten about context. Question: I create the context (`MyContext`) in file `Foo.js`. Now I want to access it in file `Bar.js` with `const navBar = useContext(MyConext)`. Am I back to the same issue of having to pass the context down? – Magnus Dec 07 '22 at 17:36
  • Ah, I probably have to export the context from `index.js`, where I created it, then import it in the other files? – Magnus Dec 07 '22 at 17:43
  • @DBS The context seems to send the ref before the ref has attached to the navBar (the context value is `null`). Could you please post an example? – Magnus Dec 07 '22 at 17:58
  • @cjl750 Thank you. Let's say I went for the approach you suggested. Let's also assume that the navbar rendered after the website body. That means the context gets set *after* the consumer requests it. So, it's null. Thoughts on how to solve that? – Magnus Dec 08 '22 at 13:12
  • 1
    @Magnus inside navbar, you will update the context once you've determined it's safe to do so. In the consumer, instead of reading the height/ref immediately when the component mounts, do it when you fire whatever function. For example, if you have a smooth-scrolling "back-to-top" button, read the nav height when you hit the button, instead of when the button first mounts. – cjl750 Dec 08 '22 at 15:49

1 Answers1

1

If you use the context API like @DBS is suggesting then you could store the element or its height in global state and grab it from any component.

Otherwise, if there are cases where the user will interact with the nav to initiate the scroll, then you could use the event object to target the nav. This is vanilla JS, but the same concept applies in React:

function getHeight(event) {
  const clickedElem = event.currentTarget
  const nav = clickedElem.closest('#nav')
  const navHeight = nav.offsetHeight
  
  console.log(navHeight + 'px')
}
<div id="nav">
  <button onclick="getHeight(event)">Click me</button>
</div>

Otherwise, I would totally go for document.querySelector('#navID'). I don't think it's inferior at all. It just depends on the use case.

But if you really want to be inferior you could still use ref and store the height value in the window object on component mount, and then you can get it there from within any component:

useEffect(() => {
  window.navHeight = nav.current.offsetHeight
}, [])
Ludolfyn
  • 1,806
  • 14
  • 20
  • 1
    Thank you! Could you perhaps add a snippet that shows how you would use context to solve it? My problem seems to be that the navRef is set by a child of the context provider. Thus, when the context provider passes the ref into the component tree, it is still null. I tried to save the navRef in state, then pass the state into the navbar, to force a rerender when it is set. No luck yet. – Magnus Dec 07 '22 at 18:39
  • 1
    As a side comment, i am generally worried that all my items will not have rendered, when the height is calculated. Not sure if that could be an issue... – Magnus Dec 07 '22 at 18:40
  • 1
    Great point about the event, by the way. That works in the few cases where I click on the navbar to scroll (as you say). I also have other links and scroll related animations where that is not the case unfortunately. – Magnus Dec 07 '22 at 18:44