简体   繁体   中英

On which point are CSS styles applied in the React lifecycle?

I'm trying to understand which lifecycle point CSS styles are starting to apply to DOM element(s).

Run onto a problem where I need to get the element's clientWidth after all styles are applied. My tests shows that I can not rely on useEffect hook, because I get inconsistent result.

I test it with a simple <did/> element, which is should take full parent width (grid container).

const divRef = useRef()

useEffect(() => {
    console.log(divRef.current.clientWidth)    
})

<div class="parent">
    <div ref={divRef} class="child" />
</div>

I expect the width === 280px, but get (lets say) 980px most of the time. If I put console.log inside a timeout everything starts to work as expected. Clearly useEffect runs before styles are applied.

Can someone clarify for me how I can get reliable result?

You can use the second argument of useEffect to keep track of the value of a variable.

const divRef = useRef()
const [divWidth, setDivWidth] = React.useState('');

useEffect(() => {
    setDivWidth(divRef.current.clientWidth)    
}, [divWidth]) // Only re-run the effect if divWidth changes

I've also found another StackOverflow question that might help you:

How to get the width of a react element

React doesn't really get any more involved with CSS than emitting class and style attributes to DOM attributes. It never "applies" CSS, and really what you probably mean could be a conglomeration of a bunch of things that could be happening in the DOM:

  • New styles taking effect from a stylesheet having loaded
  • Layout changing due to window resizing
  • Reflow happens due to fonts being applied

See What forces layout/reflow to get an idea of the scope of this.

Sadly, HTML doesn't have a DOM event for when an element's layout changes or when reflows occur, so if you need to get element dimensions, you have to hack it. One unsophisticated technique is a polling loop that periodically checks the dimensions of the DOM element. If you don't want to continuously poll, you could maybe cut off the poller after some time and add a window resize event listener to adjust the dimensions

function YourComponent() {
  const [width, setWidth] = useState(0);
  const divRef = useRef(null);

  function checkWidth() {
    if (divRef.current && divRef.current.clientWidth !== width) {
      setWidth(divRef.current.clientWidth);
    }
  }

  useEffect(() => {
    const interval = setInterval(checkWidth, 1000);
    return () => clearInterval(interval);
  }, []);

  useEffect(() => {
    window.addEventListener('resize', checkWidth);
    return () => window.removeEventListener('resize', checkWidth);
  }, []);

  return (
    <div ref={divRef}>
      ...
    </div>
  );
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM