如何反向运行react-spring 动画?

Jos*_*osh 5 typescript reactjs react-spring

我有一个动画,可以很好地从右侧移动项目并从左侧移动项目。我想在单击后退按钮时执行相反的操作,类似于从移动应用程序中的导航堆栈中弹出视图。我的代码如下,如何让动画在单击按钮时向后运行?我正在使用 React 17.0.2 和 react-spring 9.2.3 。

import React, { useState, useCallback, CSSProperties, useEffect } from "react";
import {
  useTransition,
  animated,
  AnimatedProps,
  useSpringRef,
} from "react-spring";

import styles from "../styles/components/carousel.module.css";

const Carousel: React.FC = () => {
  const [index, set] = useState(0);
  const onClick = useCallback(() => set((state) => (state + 1) % 6), []);
  const transRef = useSpringRef();
  const transitions = useTransition(index, {
    ref: transRef,
    keys: null,
    from: { opacity: 0, transform: "translate3d(100%,0,0)" },
    enter: { opacity: 1, transform: "translate3d(0%,0,0)" },
    leave: { opacity: 0, transform: "translate3d(-50%,0,0)" },
  });

  useEffect(() => {
    transRef.start();
  }, [index, transRef]);

  const pageContent: { text: string; color: string }[] = [
    { text: "one", color: "lightpink" },
    { text: "two", color: "lightblue" },
    { text: "three", color: "lightgreen" },
  ];

  const pages: ((
    props: AnimatedProps<{ style: CSSProperties }>
  ) => React.ReactElement)[] = pageContent.map((obj) => {
    return function createAnimatedDiv({ style }) {
      return (
        <animated.div style={{ ...style, background: obj.color }}>
          {obj.text}
        </animated.div>
      );
    };
  });

  const onBackClicked = useCallback(() => set((state) => (state - 1) % 6), []);

  return (
    <>
      <button onClick={onBackClicked}>Back</button>
      <div className={`flex fill ${styles.container}`} onClick={onClick}>
        {transitions((style, i) => {
          const Page = pages[i];
          return <Page style={style} />;
        })}
      </div>
    </>
  );
};

export default Carousel;
Run Code Online (Sandbox Code Playgroud)

Yur*_*kym 3

首先你需要知道动画的方向。为此,您可以使用usePrevious挂钩并比较当前索引和上一个索引。然后,根据方向,您可以返回不同的转换配置。

type Direction = 'left' | 'right' | null;

// helpers

const getDirection = (index: number, previousIndex: number): Direction => {
  if (index === previousIndex) {
    return null;
  }

  return index > previousIndex ? 'right' : 'left';
};

const getTransitionConfig = (direction: Direction): Parameters<typeof useTransition>[1] => {
  if (direction === 'right') {
    return {
      from: { opacity: 0, left: -300 },
      enter: { opacity: 1, left: 0 },
      leave: { opacity: 0, left: 300 },
    };
  }

  if (direction === 'left') {
    return {
      from: { opacity: 0, left: 300 },
      enter: { opacity: 1, left: 0 },
      leave: { opacity: 0, left: -300 },
    };
  }

  return {};
};

// component

const [index, set] = useState(0);
const previousIndex = usePrevious(index);
const animationDirection = getDirection(index, previousIndex);

const transitionConfig = useMemo(() => ({
  ref: transRef,
  keys: null,
  ...getTransitionConfig(animationDirection)
}), [animationDirection, getTransitionConfig]);

const transitions = useTransition(index, transitionConfig);
// ...
Run Code Online (Sandbox Code Playgroud)

为了简单起见,我使用了left属性。transform当然,您可以使用。