TransitionGroupとTweenMaxを使用してカスタムModalコンポーネントをアニメーション化しようとしています。JS - TransitionGroupと高次のコンポーネントに反応する
<Container>
<Content>
// modal contents in here...
</Content>
<Overlay/>
</Container>
私は<Container>
がフェードインしたいと<Content>
は下からフェードインする:モーダルの構造を理解するには、以下の仮定的、疑似構造を検討してください。理解を深めるためのビジュアルがあります。赤は、オーバーレイを表し、白は、内側の内容を表しています。
私は実際に次のコードを使用して動作するように上記のビジュアルを得た:私は上記のコードのメンテナンス性の向上のために必要
import React, { Component } from 'react';
import TransitionGroup from 'react-transition-group/TransitionGroup'; // npm install react-transition-group --save
import { TweenMax } from 'gsap'; // npm install gsap --save
class ParentChild extends React.Component {
componentWillEnter(callback) {
TweenMax.fromTo(this.parent, 0.33, {opacity: 0}, {opacity: 1, onComplete: callback});
TweenMax.fromTo(this.child, 0.33, {opacity: 0, y: 100}, {opacity: 1, y: 0, onComplete: callback});
}
componentWillLeave(callback) {
TweenMax.fromTo(this.parent, 0.33, {opacity: 1}, {opacity: 0, onComplete: callback});
TweenMax.fromTo(this.child, 0.33, {opacity: 1, y: 0}, {opacity: 0, y: 100, onComplete: callback});
}
render() {
const { size, children } = this.props;
const parentStyle = {
width: `${size}px`,
height: `${size}px`,
background: '#df4747',
display: 'flex',
alignItems: 'center',
justifyContent: 'center'
};
const childStyle = {
background: '#fff',
textAlign: 'center',
color: '#000',
width: '90%'
}
return(
<div ref={el => this.parent = el} style={parentStyle}>
<div ref={el => this.child = el} style={childStyle}>
{this.props.children}
</div>
</div>
);
}
}
class App extends Component {
constructor() {
super();
this.state = {
isVisible: false
};
this.handleToggle = this.handleToggle.bind(this);
this.handleClose = this.handleClose.bind(this);
}
handleToggle() {
this.setState({ isVisible: !this.state.isVisible });
}
handleClose() {
this.setState({ isVisible: false });
}
render() {
const { isVisible } = this.state;
return(
<div>
<TransitionGroup>
{isVisible ?
<ParentChild size="150">
<p>I wanna fade up!</p>
</ParentChild>
: null}
</TransitionGroup>
<button onClick={this.handleToggle}>Toggle Visibility</button>
</div>
);
}
}
export default App;
を高次コンポーネントの助けを借りて、私は次のように試みました。私の意見では、TweenMaxは個々のコンポーネント(fadeInHOCとfadeInUpHOC)に分離されているため、次のコードはメンテナンスが容易です。したがって、どのタイプのReactコンポーネントでも再利用できます。また、アニメーションを変更したい場合は、別のHOCを作成してラッパー機能を変更するだけです。
import React, { Component } from 'react';
import TransitionGroup from 'react-transition-group/TransitionGroup'; // npm install react-transition-group --save
import { TweenMax } from 'gsap'; // npm install gsap --save
const fadeInHOC = (Component) => {
return class extends React.Component {
componentWillEnter(callback) {
TweenMax.fromTo(this.container, 0.33, {opacity: 0}, {opacity: 1, onComplete: callback});
}
componentWillLeave(callback) {
TweenMax.fromTo(this.container, 0.33, {opacity: 1}, {opacity: 0, onComplete: callback});
}
render() {
return <Component containerRef={el => this.container = el} {...this.props}/>;
}
}
}
const fadeInUpHOC = (Component) => {
return class extends React.Component {
componentWillEnter(callback) {
TweenMax.fromTo(this.container, 0.33, {opacity: 0, y: 100}, {opacity: 1, y: 0, onComplete: callback});
}
componentWillLeave(callback) {
TweenMax.fromTo(this.container, 0.33, {opacity: 1, y: 0}, {opacity: 0, y: 100, onComplete: callback});
}
render() {
return <Component containerRef={el => this.container = el} {...this.props}/>;
}
}
}
const Parent = fadeInHOC((props) => {
const size = props.size;
const style = {
width: `${size}px`,
height: `${size}px`,
background: '#df4747',
display: 'flex',
alignItems: 'center',
justifyContent: 'center'
}
return(
<div ref={props.containerRef} style={style}>
{props.children}
</div>
);
});
const Child = fadeInUpHOC((props) => {
const style = {
background: '#fff',
textAlign: 'center',
color: '#000',
width: '90%'
}
return(
<div ref={props.containerRef} style={style}>
{props.children}
</div>
);
});
class App extends Component {
constructor() {
super();
this.state = {
isVisible: false
};
this.handleToggle = this.handleToggle.bind(this);
this.handleClose = this.handleClose.bind(this);
}
handleToggle() {
this.setState({ isVisible: !this.state.isVisible });
}
handleClose() {
this.setState({ isVisible: false });
}
render() {
const { isVisible } = this.state;
return(
<div>
<TransitionGroup>
{isVisible ?
<Parent size="150">
<Child>
<p>I wanna fade up!</p>
</Child>
</Parent>
: null}
</TransitionGroup>
<button onClick={this.handleToggle}>Toggle Visibility</button>
</div>
);
}
}
export default App;
上記コードの問題は<Child>
にfadeInUp
は、<Parent>
作品にのみ、外側のアニメーションをトリガしないことです。あなたが意図したとおりに動作させる方法を教えてください。私は別のアプローチを使うべきですか?高次コンポーネントを使用せずにParentChild
のアプローチに固執する必要がありますか?あなたのご意見を本当にありがたいです。ありがとうございました!