3

I use onscroll event in my React component like this:

import React, { Component } from 'react';
import throttle from 'lodash/throttle';

class Example extends Component {
    state = {
        navigationFixed: false,
    }

    componentDidMount() {
        window.addEventListener('scroll', this.throttledHandleScroll);
    }

    componentWillUnmount() {
        window.removeEventListener('scroll', this.throttledHandleScroll);
    }

    handleScroll = () => {
        this.contentRef && this.setState({
           navigationFixed: window.scrollY >= this.contentRef.offsetTop - 32,
    });

    throttledHandleScroll = throttle(this.handleScroll, 80); // Using lodash throttle here

    render() {
       //Some variables and components here
       ...
       <section
            className={cx(s.content, {
                [s.navigationFixed]: this.state.navigationFixed,
            })}
            id="content"
            ref={(ref) => {this.contentRef = ref}}
            >
            ...
            //Another components here
       </section>
    }
};

And this is works fine, but it get freeze sometimes, I guess it is because of handleScroll function, which fires too often. So my question is how can I optimise this code?

1
  • I think no need to add 'addEventListener' in life cycle method. You can directly bind the div like onScroll={this.handleScroll} Commented Apr 4, 2018 at 12:18

2 Answers 2

2

Try this modification to the handleScroll method.

handleScroll = () => {
    if(!this.contentRef) return;

    const navShouldBeFixed = window.scrollY >= this.contentRef.offsetTop - 32

    if(this.state.navigationFixed && !navShouldBeFixed) {
        this.setState({navigationFixed: false});
    } else if (!this.state.navigationFixed && navShouldBeFixed) {
        this.setState({navShouldBeFixed: true})
    }
}

EDIT: Less lines of code.

handleScroll = () => {
    if(!this.contentRef) return;

    const navShouldBeFixed = window.scrollY >= this.contentRef.offsetTop - 32

    if(this.state.navigationFixed && !navShouldBeFixed || 
       !this.state.navigationFixed && navShouldBeFixed) {
        this.setState({navigationFixed: navShouldBeFixed});
    }
}

This way the setState method is only fired when the UI requires a change.

Sign up to request clarification or add additional context in comments.

1 Comment

Yeah! That is much better! Thanks a lot!
0

We can reduce some more checks

handleScroll = () => {
if(!this.contentRef) return;

const navShouldBeFixed = window.scrollY >= this.contentRef.offsetTop - 32

if(this.state.navigationFixed !== navShouldBeFixed) {
    this.setState({navigationFixed: navShouldBeFixed});
}

}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.