0

I am building a React app that utilizes react-scroll on the home page. I have a series of div elements that span the entire viewport (height: 100vh; width: 100vw) that I am scrolling between, with navigation arrows that you can click to scroll through the webpage (the user still has the option to scroll manually as well). When you select any of the navigation arrows, either up or down, the window scrolls smoothly to the next position, however it stutters in the process. The issue seems to be caused when this.setState is called in my handleSectionChange method, as commenting it out resolves the issue, however it also removes the required functionality of updating the navigation arrow values.

// Located in main component and passed as a prop to component that calls it
handleSectionChange(incrementValue) {
    // Number of section being scrolled to
    var newSectionNumber = this.state.displayedSectionNumber + incrementValue
    var prevSection = homeViewSections.sections[newSectionNumber - 1];
    var nextSection = homeViewSections.sections[newSectionNumber + 1];

    // ID of section below current section to assign "to" property to in Link component
    var nextSectionId = "";

    // ID of section above current section to assign "to" property to in Link component
    var prevSectionId = "";
    var downArrowContainer = document.querySelector('.navigationArrowContainer.down')
    var upArrowContainer = document.querySelector('.navigationArrowContainer.up')

    // Repositions down arrow if intro section is displayed
    if (newSectionNumber === 0) {
        downArrowContainer.classList.add("homeIntroPosition")
    } else {
        downArrowContainer.classList.remove("homeIntroPosition")
    }

    // Displays up arrow if any section other than the first one is displayed
    if (newSectionNumber > 0) {
        prevSectionId = prevSection.referenceId
        upArrowContainer.style.visibility = "initial"
    } else {
        upArrowContainer.style.visibility = "hidden"
    }

    this.setState({
        displayedSectionNumber: newSectionNumber,
        prevSectionId: prevSectionId,
        nextSectionId: nextSectionId
    })
}

The handleSectionChange method is passed as a prop to another component which calls it (and is the only method that calls it)

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

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

handleScroll() {
    const vh = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);
    const scrollValue = window.scrollY;
    const newSectionNumber = Math.round(scrollValue / vh)
    this.animateHomeViewNavBar()
    this.setHomeViewNavLinkToActive();
    if (newSectionNumber !== this.props.currentSectionNumber)
        this.props.handleSectionChange(newSectionNumber - this.props.currentSectionNumber)
}

As you can see from the code above, it doesn't seem to be an issue with the number of times that the handleSectionChange method is called, as the if condition limits it to only when the section number is changed. I was able to pinpoint the issue to the handleChangeMethod by commenting out this.animateHomeViewNavbar and this.setHomeViewNavLinkToActive methods in various combinations, and the only way to resolve the issue was to comment out the handleSectionChange method, even with the others being called. Then, as mentioned before, the handleSectionChange method seems to remove the issue when I comment out this.setState, however that is of course necessary for the functionality. This is also the only method in the both applicable classes that calls setState, so there doesn't seem to be any conflict with that.

Sal
  • 1,471
  • 2
  • 15
  • 36
  • I don't see where `setState` is called in `handleSectionChange`, but it also looks to be incomplete code. Some tips though, using `document.querySelector` is an anti-pattern, try to use react refs if you can. Also, the scroll event can be fired ***A TON*** when scrolling, so you'll want to throttle the callback. If you can update `handleSectionChange` to be the full function code we may have a better idea what is happening. – Drew Reese Jun 06 '20 at 06:08
  • @DrewReese Yeah seems like I accidentally forgot to copy `setState` in my post, updating it to include that as well, but it is called immediately after. I tried adding the condition to prevent multiple calls to `handleScroll`, and even when I commented out `animateHomeViewNavBar` and `setHomeViewNavLinkToActive`, the page still stuttered. It was only when I commented out the `handleSectionChange` call in the `handleScroll` method that removed the stutter. – Sal Jun 06 '20 at 22:49
  • Is it possible to get this up in a running codesandbox? It may be easier to see what is happen when we can do some performance monitoring. – Drew Reese Jun 06 '20 at 22:51
  • I was unable to reproduce the issue in codesandbox unfortunately, though I did notice a few things while playing around with my code some more. The issue seems to be caused by the `react-google-charts` charts I am utilizing in one of the `div`s. When I comment out that section, the issue is barely noticeable and potentially passable. Any ideas or suggestions on handling that? – Sal Jun 07 '20 at 05:08
  • So as it turns out, the issue is reduced in Chrome, but not in Firefox, which has a pretty severe lag, though the `setState` doesn't seem to have anything to do with that. – Sal Jun 07 '20 at 17:32

0 Answers0