5

I having performance problems with React, basically I have 2 compact menus that appear when the page scroll to x distance from the top. As I see another components of the web application are doing little moves when I scroll, the cause is because they are re-rendering.

To know the distance to the top while a user does a scroll I have a eventlistener on the componentDidMount() and I think that this is causing the problem but I'm not sure, as you know react stable version is pretty new and I'm also new with this technology:

Here is some code, exactly the top bar where are nested components and triggers the compact menu bar to appear when user scolls more than 100px from top:

export default class AppTopBar extends Component {
    constructor (props){
        super(props);
        this._bind("_handleOnScrollDocument");
        this.state = {
            StatusBar: false
        }
    }

    componentDidMount() {
        if (process.env.BROWSER) {
            document.addEventListener("scroll", (e) => this._handleOnScrollDocument(e), true);
        }
    }

    _handleOnScrollDocument(e) {
        if (e.target.body.scrollTop > 100) {            
            this.setState({ StatusBar: true }); 
        } else {
            this.setState({ StatusBar: false });
        }
    }

    render() {
        return (
            <div className="aui-core-apptopbar">
                <StatusBar companies={this.props.companies} compactMenuItems={this.props.compactMenuItems} StatusBar={this.state.showCompactStatusBar}/>
                <StatusBar companies={this.props.companies} userOptions={this.props.userOptions} compactMenuItems={this.props.compactMenuItems}/>
                <MainNavBarView menuItems={this.props.menuItems}/>
            </div>
        );
    }
}

I have been investigatin and reading info about the components lifecycle and other performance stuff like this: PURERENDERMIXIN

Do you know a better way to do things to get light web applications and avoid re-rendering on scroll?

3 Answers 3

10

Let's say you create a local variable flag for your class. And then:

_handleOnScrollDocument(e) {
  let newFlag = (e.target.body.scrollTop > 100);
  if (flag !== newFlag) {
    this.setState({showCompactStatusBar: newFlag});
    flag = newFlag;
  }
};

This will cause state change (and re-rendering) only when you pass the scrollTop threshold (100) from one direction or other. Otherwise we don't need to set state at all, thus avoiding render to be called.

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

1 Comment

Great response zvona!! i also added componentWillUnmount() to remove event listeners and now the performance is much better. Thanks!!!
3

The "built-in" solution is to use the shouldComponentUpdate method which allows you to compare the current props & state of a component with the incoming props & state and then short-circuit the render method if you choose:

_handleOnScrollDocument(e) {
    // set the state no matter what
    this.setState({
        showCompactStatusBar: e.target.body.scrollTop > 100
    });
},

shouldComponentUpdate(newProps, newState) {
    // only render if the state has changed
    return this.state.showCompactStatusBar !== newState.showCompactStatusBar;
}

Comments

0

I had a scroll event on a component inside my page that had overflow: auto CSS rule. I attached scroll event listener to that component as it was guided on this blog post. However, setting last scroll position into state would ruin performances heavily.

So instead I defined last position inside class constructor and changed it there, and avoided re-rendering on each scroll.

constructor(props){
  super(props)
  this.state = { scrollDirection: 'up' }
  this.lastY = 0
}

I would only change state if direction changed.

handleListScroll(event){
  const Y = event.currentTarget.scrollTop
  const lastY = this.lastY
  if (Y > lastY) {
    scrollDirection = 'down'
    if (this.state.scrollDirection === 'up') {
      this.setState({
        scrollDirection,
      })
    }
  }
  if (Y < lastY) {
    scrollDirection = 'up'
    if (this.state.scrollDirection === 'down') {
      this.setState({
        scrollDirection
      })
    }
  }
  this.lastY = Y
}

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.