After a component is updated, on Safari and Firefox (Mac) the page changes its scroll position

Hi, community,

I keep working on my personal project to learn as much as I can Frontity to be possible to use it in my current job, and I’m facing a new issue that I can’t find a way to fix. I hope you have the experience and knowledge to give me some help.

  • Description of your issue:

After a component is updated, on Safari and Firefox (Mac) the page changes its scroll position. This component is a D3 graphic.

To reproduce the error:

  • Open the app on Safari or Firefox (Mac).
  • Scroll to the bottom of the page.
  • Filter the graphics by mode or season (there is a sticky bar on top).

You will see the page scrolls a little bit to the top. And always stays there for the next filter changes. Once you scroll down again and try to filter, the page is going scroll too again.

I’m suspecting the D3 is taking “too long” to render and the page is losing its scroll position. I’ve tried to use this (https://gist.github.com/jeffijoe/510f6823ef809e3711ed307823b48c0a) script, but no success.

  • Specific errors you’re getting in the terminal or in the browser’s console:

None.

  • A repository with the code of your project:
  • A deployed version of your site:
  • The URL of your WP REST API

https://grenal.improovement.com/wp-json/wp/v2/team?_embed=true&slug=tdk

Thank you so much,
Fernando

Sorry, everyone, I have found the issue. It’s my limitation with React (still learning).

The lines highlighted below fixed the problem.

image

image

Thank you, Fernando

Hi @nandotess85

I’ve cloned your repo and looked at your RadarChartD3 component, but I’m afraid that the issue that you’ve facing has nothing to do with Frontity, but rather with the fact that you’re re-creating the innerHTML every time you call createChart()! :slightly_smiling_face: The browser will then scroll up in order to accomodate that space that has been just destroyed.

You can just add a fixed height of 500px to your wrapper component and it solves the issue:


const Wrapper = styled.div`
  height: 500px;
  flex: 0 0 auto;
  margin-top: 30px;
  text-align: center;
  width: 100%;
  
  ... rest of your styles
`;

Also, if I may, I really really recommend that you don’t assign to this.state inside of your render functions! Calling setState re-renders your component without the need for calling forceUpdate().

To do this you can move your onMouseOver and onMouseOut functions into the component scope and call the setState inside of them like:

class RadarChartD3 extends Component {
   ... 

    // On legend item mouse over
    onMouseOver = (event) => {
      event.preventDefault();

      // Label hovered
      const index = Array.from(event.target.parentNode.children).indexOf(event.target);

      this.setState(state => { 
        return { highlight: [
          ...state.highlight.slice(0, index),
          true,
          ...state.highlight.slice(index+1)
        ]}
      });
    };

    render() {
    // .. do the render  
  }

More info: https://reactjs.org/docs/state-and-lifecycle.html#using-state-correctly

Thank you so much, Michal.

I have made the changes you recommended on the state part, and it’s working as before, but now using properly React state. Thanks once again.

But for the scroll part (my original issue), I have implemented the solution I have posted before, where I’m using getSnapshotBeforeUpdate. I prefer this one since I want to avoid have the size of the graphic hardcoded (OR duplicated).

Thanks once again and have a good weekend!

Best,
Fernando

1 Like