使用 React 和 react-transition-group 卸载动画
Animation on unmount with React and react-transition-group
我正在使用 React,我正在尝试使用 React-transition-group 创建一个 Fade
组件,以根据状态中存储的条件淡入和淡出元素:http://reactcommunity.org/react-transition-group/css-transition/
这是我现在拥有的:
import React from "react";
import ReactDOM from "react-dom";
import { CSSTransition } from "react-transition-group";
import "./styles.css";
class Example extends React.Component {
constructor(props) {
super(props);
this.state = {
mounted: false
};
}
componentDidMount() {
setTimeout(() => {
this.setState({
mounted: true
});
}, 10);
}
render() {
return (
<div className="root">
<CSSTransition
in={this.state.mounted}
appear={true}
unmountOnExit
classNames="fade"
timeout={1000}
>
{this.state.mounted ? (
<div>
<button
onClick={() => {
this.setState({
mounted: !this.state.mounted
});
}}
>
Remove
</button>
<div>COMPONENT</div>
</div>
) : (
<div />
)}
</CSSTransition>
</div>
);
}
}
这是CSS
.fade-enter {
opacity: 0;
transition: opacity .5s ease;
}
.fade-enter-active {
opacity: 1;
transition: opacity .5s ease;
}
.fade-exit {
opacity: 1;
transition: opacity .5s ease;
}
.fade-exit-active {
opacity: 0;
transition: opacity .5s ease;
}
安装组件后,不透明度会从 0 过渡到 1,耗时 0.5 秒。但是当它卸载时,它不是动画的:组件没有过渡就消失了。
我用这个组件制作了一个沙箱来测试它:https://codesandbox.io/s/k027m33y23
我确信这是一个常见的情况,但我找不到在卸载时为组件设置动画的方法。如果有人有任何想法,我们将非常欢迎!
-- 编辑 --
正如@IPutuYogaPermana 所说,CSSTransition 中的条件渲染不是必需的。所以这个:
{this.state.mounted ? (
<div>
<button
onClick={() => {
this.setState({
mounted: !this.state.mounted
});
}}
>
Remove
</button>
<div>COMPONENT</div>
</div>
) : (
<div />
)}
应该是这样的:
<div>
<button
onClick={() => {
this.setState({
mounted: !this.state.mounted
});
}}
>
Remove
</button>
<div>COMPONENT</div>
</div>
组件将根据 CSSTransition 组件中的 in
属性自动安装或卸载。
这是 codesandbox 中的最终代码:https://codesandbox.io/s/62m86nm7qw
这是预料之中的,因为随着状态的改变,动画还没有开始,但是children已经消失了。
所以就像神奇的瞬间消失一样。那么我们只需要隐藏它对吗?删除条件渲染。
我查过了,节点在动画完成后自动移除。所以不需要使用条件渲染。幸运的是!代码变为:
import React from "react";
import ReactDOM from "react-dom";
import { CSSTransition } from "react-transition-group";
import "./styles.css";
class Example extends React.Component {
constructor(props) {
super(props);
this.state = {
logoIntro: true,
mounted: false
};
}
componentDidMount() {
this.setState({
mounted: true
});
}
render() {
return (
<div className="root">
<CSSTransition
in={this.state.mounted}
appear={true}
unmountOnExit
classNames="fade"
timeout={1000}
>
<div>
<button
onClick={() => {
this.setState({
mounted: !this.state.mounted
});
}}
>
Remove
</button>
<div>SOME COMPONENT</div>
</div>
</CSSTransition>
</div>
);
}
}
ReactDOM.render(<Example />, document.getElementById("root"));
我创建了一个通用的 WrapperComponent
以便您可以动画化元素的进出,而不必总是一遍又一遍地编写相同的东西。
import { useEffect, useState } from "react"
import { CSSTransition } from "react-transition-group"
export const MountAnimation = ({
children,
timeout = 300, // MATCH YOUR DEFAULT ANIMATION DURATION
isVisible = false,
unmountOnExit = true,
classNames = "transition-translate-y", // ADD YOUR DEFAULT ANIMATION
...restProps
}) => {
const [isMounted, setIsMounted] = useState(isVisible)
useEffect(() => setIsMounted(isVisible), [isVisible])
return (
<CSSTransition
in={isMounted}
timeout={timeout}
classNames={classNames}
unmountOnExit={unmountOnExit}
{...restProps}
>
<>{children}</>
</CSSTransition>
)
}
然后像这样使用它:
import { MountAnimation } from '../../path/to/component'
...
const [isElementVisible, setIsElementVisible] = useState(false)
return (
<MountAnimation isVisible={isElementVisible}>
// your content here
</MountAnimation>
)
我正在使用 React,我正在尝试使用 React-transition-group 创建一个 Fade
组件,以根据状态中存储的条件淡入和淡出元素:http://reactcommunity.org/react-transition-group/css-transition/
这是我现在拥有的:
import React from "react";
import ReactDOM from "react-dom";
import { CSSTransition } from "react-transition-group";
import "./styles.css";
class Example extends React.Component {
constructor(props) {
super(props);
this.state = {
mounted: false
};
}
componentDidMount() {
setTimeout(() => {
this.setState({
mounted: true
});
}, 10);
}
render() {
return (
<div className="root">
<CSSTransition
in={this.state.mounted}
appear={true}
unmountOnExit
classNames="fade"
timeout={1000}
>
{this.state.mounted ? (
<div>
<button
onClick={() => {
this.setState({
mounted: !this.state.mounted
});
}}
>
Remove
</button>
<div>COMPONENT</div>
</div>
) : (
<div />
)}
</CSSTransition>
</div>
);
}
}
这是CSS
.fade-enter {
opacity: 0;
transition: opacity .5s ease;
}
.fade-enter-active {
opacity: 1;
transition: opacity .5s ease;
}
.fade-exit {
opacity: 1;
transition: opacity .5s ease;
}
.fade-exit-active {
opacity: 0;
transition: opacity .5s ease;
}
安装组件后,不透明度会从 0 过渡到 1,耗时 0.5 秒。但是当它卸载时,它不是动画的:组件没有过渡就消失了。
我用这个组件制作了一个沙箱来测试它:https://codesandbox.io/s/k027m33y23 我确信这是一个常见的情况,但我找不到在卸载时为组件设置动画的方法。如果有人有任何想法,我们将非常欢迎!
-- 编辑 -- 正如@IPutuYogaPermana 所说,CSSTransition 中的条件渲染不是必需的。所以这个:
{this.state.mounted ? (
<div>
<button
onClick={() => {
this.setState({
mounted: !this.state.mounted
});
}}
>
Remove
</button>
<div>COMPONENT</div>
</div>
) : (
<div />
)}
应该是这样的:
<div>
<button
onClick={() => {
this.setState({
mounted: !this.state.mounted
});
}}
>
Remove
</button>
<div>COMPONENT</div>
</div>
组件将根据 CSSTransition 组件中的 in
属性自动安装或卸载。
这是 codesandbox 中的最终代码:https://codesandbox.io/s/62m86nm7qw
这是预料之中的,因为随着状态的改变,动画还没有开始,但是children已经消失了。
所以就像神奇的瞬间消失一样。那么我们只需要隐藏它对吗?删除条件渲染。
我查过了,节点在动画完成后自动移除。所以不需要使用条件渲染。幸运的是!代码变为:
import React from "react";
import ReactDOM from "react-dom";
import { CSSTransition } from "react-transition-group";
import "./styles.css";
class Example extends React.Component {
constructor(props) {
super(props);
this.state = {
logoIntro: true,
mounted: false
};
}
componentDidMount() {
this.setState({
mounted: true
});
}
render() {
return (
<div className="root">
<CSSTransition
in={this.state.mounted}
appear={true}
unmountOnExit
classNames="fade"
timeout={1000}
>
<div>
<button
onClick={() => {
this.setState({
mounted: !this.state.mounted
});
}}
>
Remove
</button>
<div>SOME COMPONENT</div>
</div>
</CSSTransition>
</div>
);
}
}
ReactDOM.render(<Example />, document.getElementById("root"));
我创建了一个通用的 WrapperComponent
以便您可以动画化元素的进出,而不必总是一遍又一遍地编写相同的东西。
import { useEffect, useState } from "react"
import { CSSTransition } from "react-transition-group"
export const MountAnimation = ({
children,
timeout = 300, // MATCH YOUR DEFAULT ANIMATION DURATION
isVisible = false,
unmountOnExit = true,
classNames = "transition-translate-y", // ADD YOUR DEFAULT ANIMATION
...restProps
}) => {
const [isMounted, setIsMounted] = useState(isVisible)
useEffect(() => setIsMounted(isVisible), [isVisible])
return (
<CSSTransition
in={isMounted}
timeout={timeout}
classNames={classNames}
unmountOnExit={unmountOnExit}
{...restProps}
>
<>{children}</>
</CSSTransition>
)
}
然后像这样使用它:
import { MountAnimation } from '../../path/to/component'
...
const [isElementVisible, setIsElementVisible] = useState(false)
return (
<MountAnimation isVisible={isElementVisible}>
// your content here
</MountAnimation>
)