javascript 如何在CSS转换完成后调用函数- React

wdebmtf2  于 2023-08-02  发布在  Java
关注(0)|答案(1)|浏览(119)

我有一个React应用程序,它有一个卡片网格。我添加了一些JavaScript沿着CSS转换来动画卡片翻转。点击后,卡片会翻到后面,等待2秒后自动翻回到前面。这是我的密码isQuestionAnsweredisCorrect是从父组件传递下来的属性。

const [isFlipped, setIsFlipped] = useState(false);
const [trigger, setTrigger] = useState(0);

useEffect(() => {
    if (isFlipped || !trigger) return;
    updateScore(points);
  }, [isFlipped]);

  function flipCard() {
    if (!isQuestionAnswered || !isCorrect) return;
    setIsFlipped(true);
    setTimeout(() => {
      setTrigger((prevState) => prevState + 1);
      setIsFlipped(false);
    }, 2000)
  }

字符串
我想在转换完成后运行updateScore()函数(另一个 prop )(因此在卡片翻回正面后)。但是,updateScore()函数将在isFlipped状态设置回false后立即运行。然后,updateScore()函数将isQuestionAnswered设置为false,然后才会发生翻转转换(需要0.8秒才能完成)。如何在转换完成后运行updateScore()函数?
我试过不使用useEffect钩子和trigger状态,只在flipCard函数的超时内运行updateScore()。我还尝试在updateScore()中使用setTimeout,在0.8秒延迟(转换发生的时间)后将isQuestionAnswered设置为true,但这两种方法都不起作用。
下面是当前的updateScore()函数:

function updateScore(points) {
    setScore((prevState) => prevState + points);
    setIsQuestionAnswered(false);
  }

vcudknz3

vcudknz31#

快速回答:你可以使用onTransitionEndonAnimationEnd,注意我们是如何使用React名称的。

说明

首先,我们创建一个新的状态来保存我们的timeoutId。这是一个很好的实践,以防用户导航离开我们想要取消超时的页面。

const [savedTimeoutId, setSavedTimeoutId] = useState(0)

字符串
然后我们修改flipCard函数,在它启动之前清除旧的超时,然后它将通过将savedTimeoutId返回到调度函数来设置savedTimeoutId。阅读更多基于上一个状态更新状态- React。
我们还修改了useEffect,以便在我们可以翻回前面之前卸载组件时取消超时。

const [savedTimeoutId, setSavedTimeoutId] = useState(0)
  function flipCard() {
    // if (!isQuestionAnswered || !isCorrect) return;
    setIsFlipped(true);
    setSavedTimeoutId((prev) => {
      // if we already have a timeout, cancel it
      if (prev !== 0) clearTimeout(prev);
      // start a new timeout and set it to savedTimeoutId
      return setTimeout(() => {
        setIsFlipped(false)
      }, 2000)
    })
  }

  useEffect(() => {
    // if we move away from this page before we flip back to the
    // front, properly dispose of the setTimeout
    return () => {
      clearTimeout(savedTimeoutId);
    }
  }, [savedTimeoutId])


最后,当我们翻到前面时,将一些功能onTransitionEnd附加到updateScore

return (
    <>
      <span>Score</span>
      <span> {score}</span>
      <br />
      <button
        className="test"
        onClick={() => {
          // setIsFlipped((prev) => !prev);
          flipCard(true);
        }}
      >
        Flip Card
      </button>
      <div
        className={isFlipped ? "flipped card" : "card"}
        onTransitionEnd={() => {
          // Only update score after flipping to front
          if (!isFlipped) {
            // can easily swap for updateScore function or anything else
            setScore(score + 1);
          }
        }}
      >
        Card Front
      </div>
      <div className={!isFlipped ? "flipped card" : "card"}>Card Back</div>
    </>
  );


请注意,每次运行flipCard()时,它都会重置计时器(因为它会取消旧的超时并创建一个新的超时)。根据需要进行修改。

View demo at CodeSandbox

相关问题