0

I try to animate a div with reactjs using async data via redux and it's not clear to me when can I have a reference to the virtual dom on state loaded.

In my case I have a div with id header where I would like to push down the container when data was populated.

If I try in componentDidMount than I get Cannot read property 'style' of undefined because componentDidMount still having a reference to an on load container

class HomePage extends React.Component {

    constructor(props) {
        super(props);

        this.state = {
            sliderLength: null
        }
    }

    componentDidMount() {
        this.props.actions.getSlides()


        if(this.header) {

            setTimeout(function() {
                this.header.style.bottom = -(this.header.clientHeight - 40) + 'px';
            }, 2000);
        }
            //header.style.bottom = -pushBottom+'px';

    }


    componentWillReceiveProps(nextProps) {
        let {loaded} = nextProps
        if(loaded === true ) {
            this.animateHeader()
        }
    }

    animateHeader() {

    }

    componentWillMount() {
        const {slides} = this.props;
        this.setState({
            sliderLength: slides.length,
            slides: slides
        });
    }


    render() {
        const {slides, post, loaded} = this.props;

        if(loaded ===true ) {

            let sliderTeaser = _.map(slides, function (slide) {
                if(slide.status === 'publish') {
                    return  <Link  key={slide.id}  to={'portfolio/' + slide.slug}><img key={slide.id} className="Img__Teaser" src={slide.featured_image_url.full} /></Link>
                }
            });

            let about = _.map(post, function (data) {
                return data.content.rendered;
            })

            return (
                <div className="homePage">
                    <Slider columns={1}  autoplay={true} post={post} slides={slides} />

                    <div id="header" ref={ (header) => this.header = header}>
                        <div className="title">Title</div>
                        <div className="text-content">
                            <div dangerouslySetInnerHTML={createMarkup(about)}/>
                        </div>

                        <div className="sliderTeaser">
                            {sliderTeaser}
                        </div>

                        <div className="columns">
                            <div className="column"></div>
                            <div className="column"></div>
                            <div className="column"></div>
                        </div>

                    </div>

                    <div id="bgHover"></div>
                </div>
            );
        } else {
            return <div>...Loading</div>
        }

    }
}

function mapStateToProps(state) {
    return {
        slides: state.slides,
        post: state.post,
        loaded: state.loaded
    };
}

function mapDispatchToProps(dispatch) {
    return {
        actions: bindActionCreators(slidesActions, dispatch)
    };
}

function createMarkup(markup) {
    return {__html: markup};
}

export default connect(mapStateToProps, mapDispatchToProps)(HomePage);

How do I deal in this case with states?

Between I found a solution but not sure if is the right workaround

componentDidUpdate() {
        if(this.header) {
            setTimeout(function() {
                this.header.style.bottom = -(this.header.clientHeight - 35) + 'px';
            }, 2000);
        }
    }
fefe
  • 8,755
  • 27
  • 104
  • 180

2 Answers2

0

If you are trying to animate a div why are you trying to access it by this.header just use the javaScript's plain old document.getElementById('header') and then you can play around with the div.

aditya
  • 339
  • 2
  • 12
  • I there is no header. why do you think that would make some difference. Yes I already tried, will not work – fefe May 27 '17 at 07:45
0

In general, try to avoid using ref as much as possible. This is particularly difficult if you're new to React but with some training, you'll find yourself not needing it.

The problem with modifying the styles like you're doing is that when the component will render again your changes will be overwritten.

I would create a new state property, say state.isHeaderOpen. In your render method you will render the header differently depending on the value of this header e.g.:

render () {
  const {isHeaderOpen} = this.state
  return (
    <header style={{bottom: isHeaderOpen ? 0 : 'calc(100% - 40px)'}}>
  )
}

Here I'm using calc with percentage values to get the full height of the header.

Next, in your componentDidMount simply update the state:

componentDidMount () {
  setTimeout(() => this.setState({isHeaderOpen: false}), 2000);
}

In this way, the component will render again but with the updated style.

Another way is to check if the data has been loaded instead of creating a new state value. For example, say you're loading a list of users, in render you would write const isHeaderOpen = this.state.users != null.

Gio Polvara
  • 23,416
  • 10
  • 66
  • 62
  • Hi thanks for feedback! I already have a state variable which is provided by redux(`loaded`) action I would like to rely on this. the new state variable how would know about if async data is loaded? – fefe May 27 '17 at 09:42
  • If you have a `loaded` variable you can access it in the `render` method. Just do `const isHeaderOpen = this.state.loaded` and then the code is the same. – Gio Polvara May 27 '17 at 09:55
  • If you're learning about React I recommend you to don't use Redux in the beginning. Just use component's internal state. Once you understand how things work add Redux or some other state manager. It will be much easier to grasp all the concepts. – Gio Polvara May 27 '17 at 09:57
  • okay this will work, but this will not allow me to make calculation on DOM element. As I read about they are couple of ways to know about if component did rerendered(`componentWillReciveProps, componentDidUpdate``) – fefe May 27 '17 at 10:03
  • I made a little bin, see if it can help to clarify https://www.webpackbin.com/bins/-Kl8ZDcdkkTQJpBb0Bdd – Gio Polvara May 27 '17 at 11:14
  • thanks for the example! My issue is a bit different but you provided some useful ideas – fefe May 27 '17 at 12:21