Monday, 28 June 2021

React multiple refs getting div height not accurate

I have a React setup which attempts to reduce re-renders to a minimum. And I'm trying to imperatively animate some big divs on scroll. For this I need to know the height of the child elements but I'm struggling to get an accurate measurement using getBoundingClientRect().height.

I've logged exactly where the inaccuracies happen and when the values are logged correctly in the full file repro here: https://codesandbox.io/s/stupefied-wilson-qzb1i?file=/src/components/CaseWrapper/index.js:756-836 (Reload a few times to get the discrepancy in the console)

enter image description here

Some notes

  • I know the child height calculation stems from elements loading at different speeds such as images causing the child height to be displayed as wrong
  • I tried using React.useCallback to get mutated values but couldnt get it work without causing rerenders
  • I tried getting the values using resizeObserver but the initial numbers were still wrong.

The setup is fairly straightforward:

It starts with some data:

let cases = new Map([
  [
    "home",
    {
      name: "Home",
      slug: "home",
      component: Home,
      bg: "#eee",
      color: "#111"
    }
  ],
  [...],
  [...]

The data is used to create refs

  const myRefs = React.useRef([]);
  myRefs.current = [...cases].map(
    (i) => myRefs.current[i] ?? React.createRef()
  );
  <CaseWrapper>
    {[...cases].map((v, i) => {
      return (
        <Case
          key={v[1].slug}
          data={v[1]}
          ref={myRefs.current[i]}
          index={i}
        ></Case>
      );
    })}
  </CaseWrapper>

Inside Case.js I'm using a forwardRef to be able to use the values in the parent

export const Case = React.forwardRef(({ index, data }, ref) => {

In my parent component CaseWrapper.js I'm getting the ref and putting on a getBoundingClientRect() which only renders once, and the wrong number.

const CaseWrapper = ({ children }) => {

  React.useEffect(() => {
    const childSum = children.reduce((acc, child) => {
      console.log(child.key, child.ref.current.getBoundingClientRect().height);
        ...

At the end of the day the goal is to have a performant way to measure the height of the children that are inside <CaseWrapper/> and ideally on browser resize too. So far I've found pretty much nothing that would solve this problem somewhat elegantly without relying on some 3rd party hooks.

Any help is much appreciated, Thanks!



from React multiple refs getting div height not accurate

No comments:

Post a Comment