Why does this react-spring animation change its margin-top during an animation?

942 Views Asked by At

I have a react-spring animation that consists in make a component appear while sliding. But during this animation, the component change its margin top before going back to normal. How to fix this?

Here is the code & a sandbox:

import React, { useEffect, useMemo, useState } from "react";
import styled, { css, keyframes } from "styled-components";
import { animated, useTransition } from "react-spring";

const Tabs = styled.div`
  display: flex;
  margin-bottom: 12px;
`;

const Tab = styled.button<{ active: boolean }>`
  margin: 0 4px;
  border-bottom: 1px solid transparent;
  font-weight: ${({ active }) => active && 600};
  cursor: pointer;
  background: transparent;
  border: 0;
  &:focus {
    outline: none !important;
  }
`;

export default function Inbox() {
  const [tab, setTab] = useState(0);

  const transitions = useTransition(tab, (p) => p, {
    from: { opacity: 0, transform: "translate3d(100%,0,0)" },
    enter: { opacity: 1, transform: "translate3d(0%,0,0)" },
    leave: { opacity: 0, transform: "translate3d(-50%,0,0)" }
  });

  const getList = (name: string) => <div>{name}</div>;

  const pages = [
    ({ style }) => (
      <animated.div style={style}>{getList("test 1")}</animated.div>
    ),
    ({ style }) => (
      <animated.div style={style}>{getList("test 2")}</animated.div>
    )
  ];

  return (
    <>
      <Tabs>
        <Tab onClick={() => setTab(0)} active={tab === 0}>
          Unread
        </Tab>
        <Tab onClick={() => setTab(1)} active={tab === 1}>
          All
        </Tab>
      </Tabs>
      {transitions.map(({ item, props, key }) => {
        const Page = pages[item];
        return <Page key={key} style={props} />;
      })}
    </>
  );
}

The sandbox: https://codesandbox.io/s/amazing-ride-hwbv2?file=/src/App.tsx

1

There are 1 best solutions below

2
On BEST ANSWER

It is not the margin top you see. It is the old component moving to the left side and changing opacity, but it is still there. Finally it is unmounted in that moment the new component is taking its vertical place. Most of the time we use absolute positionig that the old and new components are on top of each other. This way there is no bump at the unmount. Something like this:

from: { opacity: 0, transform: "translate3d(100%,0,0)", position: "absolute" },