React - 动画安装和卸载单个组件 [英] React - animate mount and unmount of a single component
问题描述
这么简单的事情应该很容易完成,但我对它的复杂程度感到困惑.
我想做的就是为安装和安装动画制作动画.卸载 React 组件,就是这样.以下是我到目前为止所尝试的以及为什么每个解决方案都不起作用的原因:
ReactCSSTransitionGroup
- 我根本没有使用 CSS 类,它都是 JS 样式,所以这行不通.ReactTransitionGroup
- 这个较低级别的 API 很棒,但它要求您在动画完成时使用回调,因此仅使用 CSS 过渡在这里不起作用.总是有动画库,这就引出了下一点:- GreenSock - 许可对 IMO 的商业用途过于严格.
- React Motion - 这看起来很棒,但是
TransitionMotion
对我的需要来说非常混乱且过于复杂. - 当然,我可以像 Material UI 那样做一些诡计,元素被渲染但保持隐藏(
left: -10000px
),但我不想走那条路.我认为它很笨拙,我希望卸载我的组件,以便它们清理并且不会弄乱 DOM.
我想要一些容易实现的东西.在安装时,为一组样式设置动画;在卸载时,为相同(或另一组)样式设置动画.完毕.它还必须在多个平台上具有高性能.
我在这里撞到了一堵砖墙.如果我遗漏了什么并且有一种简单的方法可以做到这一点,请告诉我.
这有点冗长,但我已使用所有本机事件和方法来实现此动画.没有 ReactCSSTransitionGroup
、ReactTransitionGroup
等
我用过的东西
- React 生命周期方法
onTransitionEnd
事件
工作原理
- 根据传递的挂载道具(
mounted
)和默认样式(opacity: 0
)挂载元素 - 挂载或更新后,使用
componentDidMount
(componentWillReceiveProps
进行进一步更新)以超时(opacity: 1
)更改样式(opacity: 1
)使其异步). - 卸载时,传递一个prop给组件标识卸载,再次更改样式(
opacity: 0
),onTransitionEnd
,从DOM中移除卸载元素.
继续循环.
仔细阅读代码,你就会明白.如果需要任何说明,请发表评论.
希望这会有所帮助.
class App extends React.Component{构造函数(道具){超级(道具)this.transitionEnd = this.transitionEnd.bind(this)this.mountStyle = this.mountStyle.bind(this)this.unMountStyle = this.unMountStyle.bind(this)this.state ={//基础css显示:真实,风格 :{字体大小:60,不透明度:0,过渡:'all 2s Easy',}}}componentWillReceiveProps(newProps) {//检查已安装的道具if(!newProps.mounted)return this.unMountStyle()//当mounted prop为false时调用outro动画this.setState({//当挂载的 prop 为真时重新挂载节点显示:真实})setTimeout(this.mountStyle, 10)//调用进入动画}unMountStyle() {//用于卸载动画的 cssthis.setState({风格: {字体大小:60,不透明度:0,过渡:'全1s轻松',}})}mountStyle() {//用于安装动画的 cssthis.setState({风格: {字体大小:60,不透明度:1,过渡:'全1s轻松',}})}componentDidMount(){setTimeout(this.mountStyle, 10)//调用进入动画}过渡结束(){if(!this.props.mounted){//当mounted props为false时,移除transition端的节点this.setState({显示:假})}}使成为() {返回 this.state.show &&<h1 style={this.state.style} onTransitionEnd={this.transitionEnd}>你好</h1>}}class Parent 扩展 React.Component{构造函数(道具){超级(道具)this.buttonClick = this.buttonClick.bind(this)this.state = {showChild:真实,}}按钮点击(){this.setState({showChild: !this.state.showChild})}使成为(){返回 <App onTransitionEnd={this.transitionEnd}mounted={this.state.showChild}/><button onClick={this.buttonClick}>{this.state.showChild ?'卸载': '安装'}</button>}}ReactDOM.render( , document.getElementById('app'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.3.2/react-with-addons.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script><div id="app"></div>
Something this simple should be easily accomplished, yet I'm pulling my hair out over how complicated it is.
All I want to do is animate the mounting & unmounting of a React component, that's it. Here's what I've tried so far and why each solution won't work:
ReactCSSTransitionGroup
- I'm not using CSS classes at all, it's all JS styles, so this won't work.ReactTransitionGroup
- This lower level API is great, but it requires you to use a callback when the animation is complete, so just using CSS transitions won't work here. There are always animation libraries, which leads to the next point:- GreenSock - The licensing is too restrictive for business use IMO.
- React Motion - This seems great, but
TransitionMotion
is extremely confusing and overly complicated for what I need. - Of course I can just do trickery like Material UI does, where the elements are rendered but remain hidden (
left: -10000px
) but I'd rather not go that route. I consider it hacky, and I want my components to unmount so they clean up and are not cluttering up the DOM.
I want something that's easy to implement. On mount, animate a set of styles; on unmount, animate the same (or another) set of styles. Done. It also has to be high performance on multiple platforms.
I've hit a brick wall here. If I'm missing something and there's an easy way to do this, let me know.
This is a bit lengthy but I've used all the native events and methods to achieve this animation. No ReactCSSTransitionGroup
, ReactTransitionGroup
and etc.
Things I've used
- React lifecycle methods
onTransitionEnd
event
How this works
- Mount the element based on the mount prop passed(
mounted
) and with default style(opacity: 0
) - After mount or update, use
componentDidMount
(componentWillReceiveProps
for further updates)to change the style (opacity: 1
) with a timeout(to make it async). - During unmount, pass a prop to the component to identify unmount, change the style again(
opacity: 0
),onTransitionEnd
, remove unmount the element from the DOM.
Continue the cycle.
Go through the code, you'll understand. If any clarification is needed, please leave a comment.
Hope this helps.
class App extends React.Component{
constructor(props) {
super(props)
this.transitionEnd = this.transitionEnd.bind(this)
this.mountStyle = this.mountStyle.bind(this)
this.unMountStyle = this.unMountStyle.bind(this)
this.state ={ //base css
show: true,
style :{
fontSize: 60,
opacity: 0,
transition: 'all 2s ease',
}
}
}
componentWillReceiveProps(newProps) { // check for the mounted props
if(!newProps.mounted)
return this.unMountStyle() // call outro animation when mounted prop is false
this.setState({ // remount the node when the mounted prop is true
show: true
})
setTimeout(this.mountStyle, 10) // call the into animation
}
unMountStyle() { // css for unmount animation
this.setState({
style: {
fontSize: 60,
opacity: 0,
transition: 'all 1s ease',
}
})
}
mountStyle() { // css for mount animation
this.setState({
style: {
fontSize: 60,
opacity: 1,
transition: 'all 1s ease',
}
})
}
componentDidMount(){
setTimeout(this.mountStyle, 10) // call the into animation
}
transitionEnd(){
if(!this.props.mounted){ // remove the node on transition end when the mounted prop is false
this.setState({
show: false
})
}
}
render() {
return this.state.show && <h1 style={this.state.style} onTransitionEnd={this.transitionEnd}>Hello</h1>
}
}
class Parent extends React.Component{
constructor(props){
super(props)
this.buttonClick = this.buttonClick.bind(this)
this.state = {
showChild: true,
}
}
buttonClick(){
this.setState({
showChild: !this.state.showChild
})
}
render(){
return <div>
<App onTransitionEnd={this.transitionEnd} mounted={this.state.showChild}/>
<button onClick={this.buttonClick}>{this.state.showChild ? 'Unmount': 'Mount'}</button>
</div>
}
}
ReactDOM.render(<Parent />, document.getElementById('app'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.3.2/react-with-addons.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>
这篇关于React - 动画安装和卸载单个组件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!