简体   繁体   中英

Making an animation between states with React Transition Group, the animations overlap with each other

I have a simple component with some buttons that display text: You click on each different button whenever we want to display different text and I would like to have a simple fade animation when the text switches.

What I am getting instead is a weird overlap between the two states where one appears while the other is disappearing.

This is what my original code looks like within the component:

export default function MyComponent() {
  const options = { option1: [OPTION1], option2: [OPTION2], option3: [OPTION3]};
  
  const [selectedOption, setSelectedOption] = React.useState("option1");

  return (
    <div>
      <button onClick={() => setSelectedOption("option1")}>Option 1</button>
      <button onClick={() => setSelectedOption("option2")}>Option 2</button>
      <button onClick={() => setSelectedOption("option3")}>Option 3</button>

      {Object.keys(options).map((option) => (
        <CSSTransition
          in={option === selectedOption}
          key={option}
          timeout={1000}
          classNames="test"
          mountOnEnter
          unmountOnExit
        >
          <div key={option} className="test">
            {options[option]}
          </div>
        </CSSTransition>
      ))}
    </div>
  );
}

The alternative way of getting around this is only displaying the {options[option]} tag within the CSSTransition component if it is the selectedOption , basically:

{option === selectedOption && options[option]}

But with that I lose the exit animation before the next one appears. Anyway, all this to say, how could I get a transition out and a transition in smoothly between two states?

Here is a sample of what I currently have.

You can make use of the delay property on the transition to have the "exit" and "enter" animations occur sequentially. Each one will take half of the total duration. "enter" will have a delay such that it won't start until the "exit" has finished.

Since only one is visible at a time it looks silly if they are stacked vertically. We want one on top of the other. I struggled with the jerky height and I can only get it smooth if the two options are inside of a fixed-height container.

.test-container {
  position: relative;
  height: 100px;
}
.test {
  position: absolute;
}
.test-enter, .test-appear {
  opacity: 0;
  transform: scale(1.1);
}
.test-enter-active, .test-appear-active {
  opacity: 1;
  transform: scale(1);
  transition: opacity 500ms ease-in-out 500ms, transform 1000ms;
}
.test-exit {
  opacity: 1;
  transform: scale(1);
}
.test-exit-active {
  opacity: 0;
  transform: scale(0.9);
  transition: opacity 500ms ease-in-out 0ms, transform 1000ms;
}

All that I changed in your JS was adding the container div.

<div className="test-container">
  {Object.keys(options).map((option) => (...))}
</div>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM