0

I am trying to get the height of SelectedCard component only after it has completed rendering. There can be up to 3 of these and trying to grab the highest value between the 3.

While it is still rendering, I am just showing some shimmering effect.

Problem is, the height value is coming up inconsistently.

The correct value should be 160 in the example I am trying and it works about 50% of the time. I am just trying with 1 SelectedCard component, not even 3.

But intermittently I see the values 39 and 85 instead of 160 for height. Believe it is capturing the value during the shimmer effect and the 85 is probably durning mid rendering.

How can I ensure to wait and always get the 160 value for the height?

I tried with useEffect and same outcome.

Tried with timeout too inside useEffect to wait 6 seconds and this is consistently works now.

  useLayoutEffect(() => {
    setTimeout(() => {
      let height = 0;
      setMinHeight(height);
      cardRefs.current.forEach(ref => {
        if (ref) {
          height = Math.max(height, ref.clientHeight);
        }
      });
      console.log(`ktest: maxHeight: ${height}`)
      setMinHeight(height);
    }, 6000)
  }, [comparedCardsData, numberOfColumns]);

But it has an undesired effect where some styling suddenly shifts after 6 seconds.
Besides I prefer not to be randomly inserting wait time like 6 seconds. With some network lags even 6 seconds may not suffice.

What is the issue here, could I get some help with this pls.

I am looking to not use timeout and be able to get a consistent value for height.

import React, {useLayoutEffect, useRef, useState,} from 'react';
import {compose} from 'redux';
import {connect} from 'react-redux';
import SelectedCard from './SelectedCard';
import {createStructuredSelector} from "reselect";

const Header1 = ({
    data,
    numberOfColumns,
  }) => {
  const [minHeight, setMinHeight] = useState(0);
  const cardRefs = useRef([]);

  useLayoutEffect(() => {
    let height = 0;
    cardRefs.current.forEach(ref => {
      if (ref) {
        height = Math.max(height, ref.clientHeight);
      }
    });
    console.log(`height: ${height}`) // differs intermittently.
    setMinHeight(height);
  }, [data, numberOfColumns]);

  return data.slice(0, numberOfColumns)
    .map((card, index) => {
      return (
        <div>
          <div ref={ref => cardRefs.current[index] = ref} style={{minHeight}}>
            <SelectedCard/>
          </div>
          {/* many other components */}
        </div>
      );
    });
};

const mapStateToProps = createStructuredSelector({
  .....
});

const mapDispatchToProps = {
  .....
};

const all = compose(
  connect(mapStateToProps, mapDispatchToProps)
);

export default all(Header1);
karvai
  • 2,417
  • 16
  • 31
  • Do a render first of the component but make sure its hidden from view but not display none. After first ender get the height – Steve Tomlin Feb 21 '23 at 17:53
  • @SteveTomlin Looking for a way to wait for render to complete. I don't want to be using timeout. – karvai Feb 21 '23 at 17:58
  • 1
    How about using [componentDidMount()](https://reactjs.org/docs/react-component.html#componentdidmount) method? It is called after a component is rendered. [Check out this thread here.](https://stackoverflow.com/questions/26556436/react-after-render-code) – Imtiaz Raqib Feb 21 '23 at 18:18
  • @ImtiazRaqib I am using functional component. That works the same as useEffect hook which doesn't provide the desired results. – karvai Feb 21 '23 at 18:26
  • It's not clear from your code snippet here what is responsible for the progressive rendering that changes your size. If this is stylesheets loading, then perhaps you're better off delaying the loading of the app until after those are loaded. If it's images, you may be best off keeping the component invisible until their `onload` events trigger. Can you provide more insight into the content of the `SelectedCard` component? – motto Feb 21 '23 at 18:27

1 Answers1

0

an example for getting height after mounting


const Table = ({onMount}) => {
  const ref = useRef()
  useEffect(() => {
      const height = window.getComputedStyle(ref.current).getPropertyValue("height");
      onMount(height);
    }
  }, [ref, onMount]);

return (<div ref={ref}>whatever</div>)
}
Steve Tomlin
  • 3,391
  • 3
  • 31
  • 63