Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use element ref inside useMemo?

I have an HTML element, nav which has a ref set in it, sideNavRef.

I also want to get a variable to control the animations of that element and for that, I'm doing this:

  const sideNavAnimation = useMemo(() => {
    if (sideNavRef.current) {
      const animations = createSideNavKeyframes({
        startingWidth: (7 * document.body.offsetWidth) / 100,
        endingWidth: 55,
      });
      const animation = sideNavRef.current.animate(animations.animation);
      animation.pause();
      return animation;
    }
  }, []);

The createSideNavKeyframes returns a keyframes array with calculated easing values for each step (0.1 to 1).

The easing function is this:

function easeInOutQuart(x: number): number {
  return x < 0.5 ? 8 * x * x * x * x : 1 - Math.pow(-2 * x + 2, 4) / 2;
}

Since it would need to calculate this on every render I chose to use a memoized value since it wouldn't change.

But since the dependecy array is empty, it means that in the first render the value for the ref is still undefined and so the animations will be undefined as well.

Is there a better way to make this work?

like image 489
LoyalPotato Avatar asked Jun 05 '26 12:06

LoyalPotato


1 Answers

Your function is registered with sideNavRef.current still not defined because useMemo runs before the component renders. You could add sideNavRef.current in the dependency array, to ask useMemo to create a new version of your function, but for that, your component should re-render somehow, cause sideNavRef.current changing won't trigger a re-render and useMemo check its dependency only on renders.

You could use a state called componentRendred for example, add it in the dependency array, and change its value in a useEffect, like so:

const [componentRendred, setComponentRendred] = useState(false);
 const sideNavAnimation = useMemo(() => {
    if (sideNavRef.current) {
      const animations = createSideNavKeyframes({
        startingWidth: (7 * document.body.offsetWidth) / 100,
        endingWidth: 55,
      });
      const animation = sideNavRef.current.animate(animations.animation);
      animation.pause();
      return animation;
    }
  }, [componentRendred]);
useEffect(()=>{
  setComponentRendred(true);
},[])
like image 50
yousoumar Avatar answered Jun 07 '26 00:06

yousoumar



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!