React 17.0.2 功能组件仅在首次渲染时播放 CSS 动画

React 17.0.2 Functional Component Only Plays CSS Animation on First Render

我希望能够在用户回答问题后向他们显示文本反馈,然后在他们每次回答时淡出文本。我正在尝试一个非常简单的情况,从我在每个问题后播放静态反馈的地方开始。 div 之间的文本显示,然后在组件初始渲染后淡出,但在后续渲染中不显示文本并且不会出现动画(我使用的是 Chrome)。我可以确认组件在每个周期后都使用 Chrome 开发工具重新渲染,我可以在 DOM 中看到文本。我正在使用转发,以便在动画结束时文本将保持不可见。我要解决的问题是为什么动画只在第一个渲染周期之后发生,我需要做什么才能在每次组件渲染时都进行动画处理?其他细节是该应用程序使用 Redux 并且所有组件都可以正常运行。

这是一个沙箱,显示了问题的样子。在这种情况下,我将道具传递给反馈组件以强制其重新渲染。每次您输入文本输入时,它都会强制反馈组件重新渲染(我通过登录控制台确认)但动画仅在第一次渲染时播放。

https://codesandbox.io/s/reactcssanimationissue-zwc6l?file=/src/UserFeedBack/UserFeedBackComponent.js

    import React from "react";
    import classes from "./AnswerFeedBackComponent.module.css";
    
    const AnswerFeedBackComponent = () => {          
      
        return (
            <div className={classes.CorrectAnswer} >Correct!</div> 
         );    
    }
    export default AnswerFeedBackComponent;
---
.CorrectAnswer{
    color:green;
    font-weight: bold;
    animation: fade 3s linear forwards;
    opacity: 1;
}

@keyframes fade {
    0% {
        opacity: 1;
    }
    100%{
        opacity: 0;
    }
}

在重新渲染期间,React 仅查找已更改的元素。如果不是,则它不会更新元素,即使它重新呈现也是如此。

所以你可以让反应知道这个元素已经改变,或者卸载并再次安装组件。我已经提供了两个用例。

  1. 您可以添加具有 运行dom 值的 key 道具,以便 React 在每次重新渲染时知道它的不同,从而重新安装组件。这是快速和 hacky 并且有效。
const UserFeedBackComponent = (props) => {
  console.log("UserFeedBackComponent rendered");
  const rand = Math.random();

  return (
    <div className={classes.Border} key={rand}>
      <div className={classes.CorrectAnswer}>Correct!</div>
    </div>
  );
};

https://codesandbox.io/s/reactcssanimationissue-forked-9jufd

  1. 另一种方法是在它不可见后将其从 dom 中删除。逻辑将由其父级处理,InputComponent
import React, { useState } from "react";
import UserFeedBackComponent from "../UserFeedBack/UserFeedBackComponent";
import classes from "./InputComponent.module.css";

const InputComponent = () => {
  const [currentInput, setCurrentInput] = useState("");
  const [showNotification, setShowNotification] = useState(false);

  const inputHandler = (event) => {
    setCurrentInput(event.target.value);
    setShowNotification(true);
    setTimeout(() => {
      setShowNotification(false);
    }, 3000);
  };

  return (
    <React.Fragment>
      <input type="text" value={currentInput} onChange={inputHandler} />
      <div className={classes.Output}>{"Output is " + currentInput}</div>
      {showNotification && <UserFeedBackComponent text={currentInput} />}
    </React.Fragment>
  );
};

export default InputComponent;

每次需要显示通知时,只需将showNotification设置为true,然后通过setTimeout再次设置为false即可触发在你的动画持续时间之后,即 3s。这要好得多,因为没有陈旧的不可见元素污染您的 dom。您仍然可以对其进行迭代和改进。

https://codesandbox.io/s/reactcssanimationissue-forked-mejre