【问题标题】:React Breathing Animation反应呼吸动画
【发布时间】:2021-07-02 00:40:52
【问题描述】:

我正在尝试使用 React/Typescript 创建一个呼吸应用程序。我不想使用 React Native。

我将呼吸圈设置为组件,并且我为每个圈设置了自己的动画(如果有的话)。 (我不提供此代码,因为这不是问题)

我遇到的问题是让动画无限运行,同时保持 setTimeout() 的延迟。 (见下面的代码)

import React, { useState, useEffect } from "react";
import "./App.css";
import {
  BreatheInCircle,
  BreatheHoldInCircle,
  BreatheOutCircle,
  BreatheHoldOutCircle,
} from "./BreatheCircle";

const circles = [
  <BreatheInCircle/>,
  <BreatheHoldInCircle />,
  <BreatheOutCircle />,
  <BreatheHoldOutCircle />,
];

const App = () => {

  const [circleArray] = useState(circles);
  const [displayElement, setDisplayElement] = useState(<div></div>);
  const [index, setIndex] = useState(0);
  
  useEffect(() => {
    setTimeout(() => {
      setDisplayElement(circleArray[index]);
      setIndex(index + 1);
    }, 4000);
  });

  return (
    <div>
      {displayElement}
    </div>
  );
}

export default App;`enter code here`

当我现在运行它时,它将为每个组件运行一次 useEffect,然后停止。我需要动画重复,直到我停止它。

编辑

我能够解决我遇到的延迟问题,但我仍然需要循环方面的帮助。以下是更新后的代码,延迟时间有所变化。

const App = () => {

  const [circleArray] = useState(circles);
  const [displayElement, setDisplayElement] = useState(<div></div>);
  const [index, setIndex] = useState(0);

  const timeoutDelays = [0, 4000, 4000, 4000, 4000];

  const changeCircle = () => {
    setCircle(circles[index]);
    setIndex(index + 1);
  };

  useEffect(() => {
    setTimeout(changeCircle, timeoutDelays[index]);
  }, [index]);

如果 setInterval 仍然是一个解决方案,我想知道如何实现它。现在,它运行一次,然后停止。

【问题讨论】:

    标签: reactjs typescript animation


    【解决方案1】:

    为什么您尝试超时而不是间隔? 还将一些数据从父组件发送到子组件以更新动画,我认为这并不重要。

    【讨论】:

    • 当我使用 setInterval 时,在渲染下一个组件时,组件之间会闪烁,当动画完成时(我不确定为什么会发生这种情况),它会随机闪烁其中一个成分。看起来它吓坏了我。我尝试使用 Timeout,只是想看看会发生什么,而且效果几乎完美。
    • 如果你想使用 setTimeout 然后在设置索引之后再次调用 setTimeout 函数。但这不好。 setTimout 只调用一次,但一旦完成,您就可以调用函数
    • 你能给我举个例子吗?我不明白你的意思。
    【解决方案2】:

    下面是我用来解决它的最终代码。它正在使用 setInterval,我只需要正确执行即可。我赞成 user8119020 的回答,因为他们引导我找到了解决这个问题的正确方法。

    const BreatheCircles: FC = () => {
      const [circle, setCircle] = useState(<div></div>);
      const [index, setIndex] = useState(0);
    
      const circles = [
        <BreatheInCircle />,
        <BreatheHoldInCircle />,
        <BreatheOutCircle />,
        <BreatheHoldOutCircle />,
      ];
    
      const changeCircle = () => {
        setCircle(circles[index]);
        setIndex(index + 1);
        if(index >= 3) {
            setIndex(0);
        }
      };
    
      useEffect(() => {
        const interval = setInterval(changeCircle, 4000);
        return () => clearInterval(interval);
      }, [changeCircle]);
    
      return <>{circle}</>;
    };
    

    动画开始前有一段延迟,但这不是问题。再次感谢 user8119020 的帮助。

    更新**

    大家好,我知道这有点晚了,但我找到了使用纯 CSS 的更好方法。下面是我用来创建相同呼吸函数而无需重新渲染一百万次的代码示例。

    我使用 MUI 来创建适当的样式。

    
    const breatheCircles = makeStyles((theme: Theme) =>
      createStyles({
        breatheCircle: {
          borderRadius: '50%',
          width: '30vh',
          height: '30vh',
          animation: '$breathe 17400ms infinite',
        },
        '@keyframes breathe': {
          '0%': {
            transform: 'scale(.5)',
            backgroundColor: '#71A1C9',
          },
          '24.9%': {
            backgroundColor: '#71A1C9',
          },
          '25%': {
            transform: 'scale(1)',
          },
          '25.1%': {
            backgroundColor: '#FF9833',
          },
          '50%': {
            transform: 'scale(1)',
            backgroundColor: '#FF9833',
          },
          '50.1%': {
            backgroundColor: '#000000',
          },
          '75%': {
            transform: 'scale(.5)',
            backgroundColor: '#000000',
          },
          '75.1%': {
            backgroundColor: '#FF9833',
          },
          '100%': {
            transform: 'scale(.5)',
            backgroundColor: '#FF9833',
          },
        },
      })
    );
    
    const Breathe: FC = () => {
      const classes = useStyles();
      const circleStyles = breatheCircles();
      const gender = useSelector<State>((state) => state.gender);
    
    return (
        <>
          <Header />
          <div className={classes.root}>//styled elsewhere
            <div className={classes.circles}>//styled elsewhere
              <div className={circleStyles.breatheCircle} />
              <Counter />
            </div>
            <div className={classes.buttonBar}>
              <ButtonBar />
            </div>
          </div>
        </>
      );
    };
    
    

    我只是认为社区希望看到一种更有效的方式来为这些圈子设置动画。

    谢谢!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-09
      • 2018-12-08
      • 1970-01-01
      • 2021-12-26
      • 2014-09-06
      • 1970-01-01
      相关资源
      最近更新 更多