Skip to content
Patrick Desjardins Blog
Patrick Desjardins picture from a conference

How to animate unmounting of a child with Framer Motion

Posted on: 2022-10-10

Imagine the situation where you have one parent and a direct child component. The child component has a list of elements. These elements are animated as the parent component is mounted.

The parent renders the child that renders the list of elements, and each element is animated in a staggered fashion. The tricky part is how do you animate when the parent component is unmounted to have the children unmounted that trigger the list of elements to be animated oppositely from the mounted animation?

Structure of the Prototype

First, let's define what we need. The application needs to host a component that will remain mounted. This mounted component is called Parent.

export default function App() {
  return (
    <div className="App">
      <div className="Main">
        <div className="BoxContainer">
          <Parent />
        </div>
      </div>
    </div>
  );
}

The parent contains a component that will be mounted and unmounted. The component is named Child. That is the one we want to have an animation on many items to fade in and out as the component mount and unmount.

export const Parent = () => {
  const [mountParentCount, setParentMountCount] = useState(0);
  useEffect(() => {
    console.log("Parent Mounting");
    return () => {
      console.log("Parent UnMounting");
    };
  });
  return (
    <div className="Parent">
      <Child />
      <br />
      <h3>Mounting Parent count: {mountParentCount}</h3>
      <button
        onClick={() => {
          setParentMountCount((prev) => ++prev);
        }}
      >
        Remount Parent
      </button>
    </div>
  );
};

The Parent component has a useEffect to have some insight into whether the Parent component mounts and unmounts. Otherwise, it has a useState that will force a render of the Parent. Also, there is a button. Every click changes the state making a new render of the Parent. At that point, the Child remains the same as it does not have any change and hence does not mount and unmount on the button click. We will change that soon.

Finally, we need to define the Child. Similarly, we will have a useEffect to see when the component mounts and unmounts.

export const Child = () => {
  useEffect(() => {
    console.log("Child Mounting");
    return () => {
      console.log("Child UnMounting");
    };
  });

  return (
    <ul
      className="Child"
    >
      <li key="Child1">
        <div>😊</div>
      </li>
      <li key="Child2">
        <div>🥶</div>
      </li>
    </ul>
  );
};

Mounting and Unmounting

To perform the desired effect of mounting and unmounting the Child component on the button click, React must know that the Child has changed. The usage of key does the trick. Hence, in the Parent container, we will assign a unique key property to the Child component that is crafted with the incremental state.

<Child key={"unique_" + mountParentCount} />

Animation

The animation occurs inside the Child components. The idea is to have each li having an opacity change from 0 to 1 and simultaneously have the li move from right to left with a rotating effect.