React 17.0.2 功能组件仅在首次渲染时播放 CSS 动画
React 17.0.2 Functional Component Only Plays CSS Animation on First Render
我希望能够在用户回答问题后向他们显示文本反馈,然后在他们每次回答时淡出文本。我正在尝试一个非常简单的情况,从我在每个问题后播放静态反馈的地方开始。 div 之间的文本显示,然后在组件初始渲染后淡出,但在后续渲染中不显示文本并且不会出现动画(我使用的是 Chrome)。我可以确认组件在每个周期后都使用 Chrome 开发工具重新渲染,我可以在 DOM 中看到文本。我正在使用转发,以便在动画结束时文本将保持不可见。我要解决的问题是为什么动画只在第一个渲染周期之后发生,我需要做什么才能在每次组件渲染时都进行动画处理?其他细节是该应用程序使用 Redux 并且所有组件都可以正常运行。
这是一个沙箱,显示了问题的样子。在这种情况下,我将道具传递给反馈组件以强制其重新渲染。每次您输入文本输入时,它都会强制反馈组件重新渲染(我通过登录控制台确认)但动画仅在第一次渲染时播放。
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 仅查找已更改的元素。如果不是,则它不会更新元素,即使它重新呈现也是如此。
所以你可以让反应知道这个元素已经改变,或者卸载并再次安装组件。我已经提供了两个用例。
- 您可以添加具有 运行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
- 另一种方法是在它不可见后将其从 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
我希望能够在用户回答问题后向他们显示文本反馈,然后在他们每次回答时淡出文本。我正在尝试一个非常简单的情况,从我在每个问题后播放静态反馈的地方开始。 div 之间的文本显示,然后在组件初始渲染后淡出,但在后续渲染中不显示文本并且不会出现动画(我使用的是 Chrome)。我可以确认组件在每个周期后都使用 Chrome 开发工具重新渲染,我可以在 DOM 中看到文本。我正在使用转发,以便在动画结束时文本将保持不可见。我要解决的问题是为什么动画只在第一个渲染周期之后发生,我需要做什么才能在每次组件渲染时都进行动画处理?其他细节是该应用程序使用 Redux 并且所有组件都可以正常运行。
这是一个沙箱,显示了问题的样子。在这种情况下,我将道具传递给反馈组件以强制其重新渲染。每次您输入文本输入时,它都会强制反馈组件重新渲染(我通过登录控制台确认)但动画仅在第一次渲染时播放。
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 仅查找已更改的元素。如果不是,则它不会更新元素,即使它重新呈现也是如此。
所以你可以让反应知道这个元素已经改变,或者卸载并再次安装组件。我已经提供了两个用例。
- 您可以添加具有 运行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
- 另一种方法是在它不可见后将其从 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