This Banner is For Sale !!
Get your ad here for a week in 20$ only and get upto 15k traffic Daily!!!

React animation onDestroy (removed from the DOM)


Hey and welcome to this submit about animating a transition in React when a part is destroyed, AKA faraway from the DOM.

I normally face points when making use of some fadeIn/fadeOut transition on a React part or JSX factor. As a result of when the part/factor is faraway from the DOM I can now not apply any transition.

Let’s write some primary React app with a counter which is elevated by 1 each second.
We show the counter and under it we show a react picture at any time when the rely is divisible by 3.

Demo here.

// Disable React Strict mode for this instance
perform App() {
  const [count, setCount] = useState(0);
  const [isDivisibleByThree, setIsDivisibleByThree] = useState(false);

  useEffect(() => {
    if (rely !== 0 && rely % 3 === 0) setIsDivisibleByThree(true);
  }, [count]);

  useEffect(() => {
    setInterval(() => {
      setCount((p) => (p += 1));
    }, 1000);
  }, []);

  return (
    <div
      model={{
        show: "flex",
        flexDirection: "column",
        hole: "50px",
        alignItems: "middle",
        justifyContent: "middle",
      }}
    >
      <div>
        <h1>rely is {rely}</h1>
      </div>
      <p>
        {isDivisibleByThree && (
          <img ref={imageRef} src={reactLogo} alt="react emblem"/>
        )}
      </p>
    </div>
  );
}
Enter fullscreen mode

Exit fullscreen mode

We are able to animate at any time when the <img> is seen with the next CSS.
This manner when the picture first seems it should have some slide-in animation, shifting from high to backside.

img {
  animation: slide-in 0.5s ease-in-out;
}
p {
  peak: 5rem;
  width: 5rem;
}
@keyframes slide-in {
  0% {
    opacity: 0;
    rework: translateY(-50%);
  }
  100% {
    opacity: 1;
    rework: translateY(0);
  }
}
Enter fullscreen mode

Exit fullscreen mode

So… how can we animate when the <img> factor is faraway from the DOM.

Let’s create a customized hook known as useHandleDestroyAnimated, this hook accepts a ref (from the useRef hook) from the HTML factor we want to animate on destroy.

Earlier than hiding the <img> by way of setting the isDivisibleByThree state to false, we animate its destruction after 1000ms, then, we set the state to false.

async perform sleep(ms: quantity) {
  return new Promise((resolve) => setTimeout(resolve, ms));
}

perform useHandleDestroyAnimated<T extends HTMLElement>(
  ref: MutableRefObject<T | null>
): [boolean, (_: boolean) => void] {
  const [state, setState] = useState(false);

// everytime the state or ref change, if state is true, we animate the destroy of the part.
  useEffect(() => {
    if (state) {
      handleDeletion(ref);
    }
  }, [ref, state]);

  perform handleDeletion<T extends HTMLElement>(
    factor: MutableRefObject<T | null>
  ) {
    const model = factor?.present?.model;
    if (!model) return;
    sleep(1000).then(() => {
      model.transition = "all 0.5s";
      model.rework = "translateY(-50%)";
      model.opacity = "0";
      sleep(1000).then(() => {
        setState(false);
      });
    });
  }
  return [state, setState];
}
Enter fullscreen mode

Exit fullscreen mode

Let’s add the ref from the useRef hook to the App.tsx:

const imageRef = useRef<HTMLImageElement | null>(null);
.....
.....
.....
 <p>
        {isDivisibleByThree && (
          <img ref={imageRef} src={reactLogo} alt="react emblem" />
        )}
      </p>
Enter fullscreen mode

Exit fullscreen mode

The ultimate code is:

import { useEffect, useState, MutableRefObject, useRef } from "react";
import reactLogo from "./belongings/react.svg";
import "./App.css";

async perform sleep(ms: quantity) {
  return new Promise((resolve) => setTimeout(resolve, ms));
}

const types = Object.freeze({
  opacity: "0",
  rework: "translateY(-50%)",
  transition: "all 0.5s",
});

perform useHandleDestroyAnimated<T extends HTMLElement>(
  ref: MutableRefObject<T | null>
): [boolean, (_: boolean) => void] {
  const [state, setState] = useState(false);

  useEffect(() => {
    if (state) {
      handleDeletion(ref);
    }
  }, [ref, state]);

  perform handleDeletion<T extends HTMLElement>(
    factor: MutableRefObject<T | null>
  ) {
    const model = factor?.present?.model;
    if (!model) return;
    sleep(1000).then(() => {
      model.transition = types.transition;
      model.rework = types.rework;
      model.opacity = types.opacity;
      sleep(1000).then(() => {
        setState(false);
      });
    });
  }
  return [state, setState];
}

perform App() {
  const [count, setCount] = useState(0);
  const imageRef = useRef<HTMLImageElement | null>(null);
  const [isDivisibleByThree, setIsDivisibleByThree] =
    useHandleDestroyAnimated(imageRef);

  useEffect(() => {
    if (rely !== 0 && rely % 3 === 0) setIsDivisibleByThree(true);
  }, [count]);

  useEffect(() => {
    setInterval(() => {
      setCount((p) => (p += 1));
    }, 1000);
  }, []);

  return (
    <div
      model={{
        show: "flex",
        flexDirection: "column",
        hole: "50px",
        alignItems: "middle",
        justifyContent: "middle",
      }}
    >
      <div>
        <span>rely is {rely}</span>
      </div>
      <p>
        {isDivisibleByThree && (
          <img ref={imageRef} src={reactLogo} alt="react emblem" />
        )}
      </p>
    </div>
  );
}

export default App;
Enter fullscreen mode

Exit fullscreen mode

I hope you discovered this convenient!

You’ll be able to comply with me on:

The Article was Inspired from tech community site.
Contact us if this is inspired from your article and we will give you credit for it for serving the community.

This Banner is For Sale !!
Get your ad here for a week in 20$ only and get upto 10k Tech related traffic daily !!!

Leave a Reply

Your email address will not be published. Required fields are marked *

Want to Contribute to us or want to have 15k+ Audience read your Article ? Or Just want to make a strong Backlink?