Slevin
Slevin

Reputation: 4232

How to invert animation order in react-spring's useTransitions

I want to animate the opacity of the items from number 1 to 4, but want to run it inverted (from 4 to 1) if the items are removed. I thought that the reverse flag could help, but it doesn't do anything:

import React, { useState } from "react";
import { animated, config, useTransition } from "react-spring";

export default function App() {
  const items = [1, 2, 3, 4];
  const [isToggled, setToggled] = useState(false);

  const transitions = useTransition(isToggled ? items : [], item => item, {
    config: config.gentle,
    unique: true,
    trail: 250,
    reverse: isToggled ? false : true,
    from: { opacity: 0 },
    enter: { opacity: 1 },
    leave: { opacity: 0 }
  });

  return (
    <div className="App">
      <button onClick={() => setToggled(!isToggled)}>Toggle</button>

      {transitions.map(({ item, key, props }) => (
        <animated.div key={key} style={props}>
          Issue #{item}
        </animated.div>
      ))}
    </div>
  );
}

CodeSandbox

Upvotes: 1

Views: 2695

Answers (1)

rayandrew
rayandrew

Reputation: 23

The problem with reverse method is it reverse all the content inside the array. You only need to reverse the props properties inside the result of your useTransition.

With simple array modification like this (in typescript) :

// utils/animation.ts
// or js just modify the type

import { UseTransitionResult } from 'react-spring';

export function reverseTransition<T, Result extends UseTransitionResult<T, object>>(
  arr: Result[],
): Result[] {
  const result: Result[] = [];
  for (let idx = 0; idx < arr.length; idx++) {
    result.push({
      ...arr[idx],
      props: arr[arr.length - 1 - idx].props,
    });
  }
  return result;
}

and pass the result of useTransition hooks like this :

import React, { useState } from "react";
import { animated, config, useTransition } from "react-spring";

// import above code
import { reverseTransition } from "utils/animation";

export default function App() {
  const items = [1, 2, 3, 4];
  const [isToggled, setToggled] = useState(false);

  const transitions = useTransition(isToggled ? items : [], item => item, {
    config: config.gentle,
    unique: true,
    trail: 250,
    reverse: isToggled ? false : true,
    from: { opacity: 0 },
    enter: { opacity: 1 },
    leave: { opacity: 0 }
  });

  return (
    <div className="App">
      <button onClick={() => setToggled(!isToggled)}>Toggle</button>

      {(isToggled ? transitions : reverseTransition(transitions)).map(({ item, key, props }) => (
        <animated.div key={key} style={props}>
          Issue #{item}
        </animated.div>
      ))}
    </div>
  );
}

You will get the reversed animation with the same content. I hope it helps!

Codesandbox

Notes: I am using React Spring v8, not v9 (the one that you use in your Codesandbox)

Regards

Upvotes: 2

Related Questions