React: How to trigger a useEffect by comparing two state variables?

UPDATE:
I realized what the real-problem was, I had a fade-out, fade-in animation for whenever the text updated and that was causing scrollHeight to give unpredictable results.


I am trying to animate height change for my quote machine project.
My strategy is to set the element to overflow:hidden, get the scrollHeight and then assign it to height.
Currently I am using a useEffect hook which changes the height whenever scrollHeight changes. The problem is that it works maybe half the time and sometimes it fails to update the height, which I think is due to the way React updates states.

useEffect(() => {
    setHeight("2rem");
    setScrollHeight(textRef.current.scrollHeight);
}, [props.text]);
useEffect(() => {
    setHeight(scrollHeight);
}, [scrollHeight]);

I had to set the height back to the font-size otherwise there would be an ugly space in the middle of the app whenever the height refused to update. It is a hacky approach and does not satisfy me.
Here is the result:
https://sahand-masoleh.github.io/project-quote-machine/
As you can see it sometimes refuses to update the height state for two line quotes.
Now my question is, how can I have a useEffect to constantly compare height and scrollHeight and run setHeight whenever the two values are unequal?

Isn’t the height of the p element just the same when it doesn’t run useEffect?

Try setting the p element to have height: min-content.

I guess centering it in the parent element might also work or at least look better (i.e. align-items: center on #text)

It is rather simple:

useEffect(() => {
    if (height !== scrollHeight) {
        setHeight(scrollHeight)
    }
}, [height, scrollHeight])

But I guess the real question is whether there is an easier way to accomplish what you are doing, as it looks kinda like you are interlocking many different useEffects. It is hard to read at least…

1 Like

Wouldn’t work, that works like height: auto and kills the transition animation.

Thanks! Fixed!
I guess I was thinking using a conditional inside a useEffect is wouldn’t work. :laughing:
I don’t why I was doing an unnecessary prop to state step in the middle. I edited the code in my original post.
Anyhow this is how my code looks like now and it works. Cheers!

  useEffect(() => {
    setScrollHeight(textRef.current.scrollHeight);
  }, [props.text]);
  useEffect(() => {
    if (height !== scrollHeight) {
      setHeight(scrollHeight);
    }
  }, [height, scrollHeight]);