Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React hook that runs AFTER the DOM updates

I have a React app where I am hiding/showing an element based on state, and want to do some calculations on that DOM element after the state variable changes.

I've tried using useLayoutEffect, but this still runs before the DOM has updated, so my calculations aren't useful. Is my understanding of useLayoutEffect wrong? Am I using it incorrectly?

Here's what I have

const myComponent = () => {

  const elem = useRef()
  const [isElemVisible, setIElemVisible] = useState(false)

  useLayoutEffect(() => {
    // I want this to run AFTER the element is added/removed from the DOM
    // Instead this is run before the element is actually modified in the DOM (but the ref itself has changed)

    elem.current.getBoundingClientRect() // do something with this object if it exists
  }, [elem.current])


  return (
   <div id="base-element">
    { isElemVisible && (
      <div id="element" ref={elem}></div>
    )}
   </div>
  )
}
like image 760
Adam Thompson Avatar asked Oct 20 '25 04:10

Adam Thompson


2 Answers

You can try to pass a function as ref and do stuff in that function:

const myComponent = () => {

  // other component code

  const elemRef = useCallback((node) => {
    if (node !== null) {
      // do stuff here
    }
  }, [])


  return (
   <div id="base-element">
    { isElemVisible && (
      <div id="element" ref={elemRef}></div>
    )}
   </div>
  )
}

Check out this https://reactjs.org/docs/hooks-faq.html#how-can-i-measure-a-dom-node

like image 103
Olexandr Poplavskyi Avatar answered Oct 22 '25 19:10

Olexandr Poplavskyi


An easy solution to this, is to manually check for state update in a useEffect hook:

const myComponent = () => {

  const elem = useRef()
  const [isElemVisible, setIElemVisible] = useState(false)

  useEffect(() => {
   if (isElemVisible) {
     // Assuming UI has updated:
     elem.current.getBoundingClientRect() // do something with this object
   }

  }, [isElemVisible])


  return (
   <div id="base-element">
    { isElemVisible && (
      <div id="element" ref={elem}></div>
    )}
   </div>
  )
}
like image 38
Bassem Avatar answered Oct 22 '25 18:10

Bassem