0

I want page contents in my application to transition smoothly. I have been attempting to do this using react-transition-group but I have struggled to achieve the correct implementation. The following link was informative: https://coursework.vschool.io/react-transitions-with-react-transition-group/

It shows how to make modularize and use TransitionGroup (although not both at the same time, unfortunately).

I created a demo project (based on the above link) to troubleshoot this issue. I have two items in an array ‘contactComponents’. All I am trying to do at the moment is make this information appear and disappear using the show/hide button.

Here is the main body of the code:

const contactDetails = ['Gryffindor Tower, Hogwarts','Gryffindor Tower, Hogwarts'];
const contacts = ['Harry', 'Ron'];

export default class App extends React.Component {

    constructor(props){
        super(props);
        this.state = {
            count: 0,
            showMyContact: false

        };

        this.showContact = this.showContact.bind(this);
    }

    showContact() {
        this.setState({showMyContact: !this.state.showMyContact})
    }



    render() {

        const styles = {
            container: { display: 'flex', justifyContent: 'center', width: '100vw', height: 100, flexDirection: 'column', padding: 100 },
            btn: { width: '100%', display: 'flex', justifyContent: 'center'},
            h1: { border: '2px solid blue', padding: 5, display: 'flex'}
        };

        let contactComponents = [contacts[this.state.count], contactDetails[this.state.count]];

        console.log(this.state.showMyContact)

        return (
            <div>
                <div style={ styles.container }>

                     <TransitionGroup component={null}>
                        { contactComponents.map((item, key) =>
                            <CSSTransition
                                in={this.state.showMyContact}
                                key={key}
                                timeout={800}
                                classNames={"fade"}>
                                    <h1 style={styles.h1}>
                                        {
                                            item
                                        }
                                    </h1>
                            </CSSTransition>

                        )}
                    </TransitionGroup>

                    <div style={ styles.btn }>
                        <button onClick={ this.showContact }>show/hide</button>
                    </div>
                </div>
            </div>
        )
    }
}

scss file:

.fade-appear,
.fade-enter {
    opacity: 0;
    z-index: 1;
}
.fade-appear-active,
.fade-enter.fade-enter-active {
  opacity: 1;
  transition: opacity 600ms linear 200ms;
}

.fade-exit {
    opacity: 1;
}

.fade-exit.fade-exit-active {
    opacity: 0;
    transition: opacity 200ms linear;
}

Currently, the contents appears even though showMyContact is false when the render function first calls. Changing the state of showMyContact with the show/hide button has no effect. The content does not fade in and out as expected.

This post: page transitions without React-Router

suggests it might be better to use pure css to carry out transitions rather than react-transition-group. Am I just barking up the wrong tree?

cjg
  • 3
  • 2

1 Answers1

0

I found out that using pure css transitions provides the desired solution. I do not know if a solution using TransitionGroup and CSSTransition is feasible but it doesn't look like it.

By changing the contents of the render function to:

render() {

    let contactComponents = [contacts[this.state.count], contactDetails[this.state.count]];

    let cssList = [
        "List",
        this.state.showMyContact ? "ListShow" : "ListHide"
    ];

    console.log(this.state.showMyContact);

    return (
        <div>
            <div className={"container"}>

                <List show={cssList.join(' ')} myContent={contactComponents}/>

                <div className={"btn"}>
                    <button onClick={ this.showContact }>show/hide</button>
                </div>
            </div>
        </div>
    )
}

...and adding the following const:

const List = (props) => {

return (
    <div className={props.show}>
        <h1 className={"h1"}> { props.myContent[0] } </h1>
        <h1 className={"h1"}> { props.myContent[1] } </h1>
    </div>
)};

...and importing the following css file:

.container {
    display: flex;
    justify-content: center;
    width: 500px;
    height: 100px;
    flex-direction: column;
    padding: 100px;
}

.h1 {
    border: 2px solid blue;
    padding: 5px;
    display: flex;
}

.btn {
    width: 100%;
    display: flex;
    justify-content: center;
}

.List {
    display: flex;
    flex-direction: column;
    transition: all 0.4s ease-out;
}


.ListShow {
    opacity: 1;
}

.ListHide {
    opacity: 0;
}

...I can get the desired behaviour.

cjg
  • 3
  • 2