I faced with a strange annoying issue with React - React automatically scrolls the page on re-render.
Demo app on CodeSandbox - https://codesandbox.io/s/react-scroll-bug-demo-y7u50j?file=/src/App.js
Steps to reproduce:
- Scroll the page to the middle of list, so its first element is not visible anymore.
- Wait for re-render to happen.
- See your page auto-scrolled so the first element is visible again.
Issue - React automatically scrolls the page when these conditions are met:
- I have a vertical list of items.
- List re-rendered (items change their order).
- List is visible on the screen but the first element is not visible (it is above the screen).
So, when the list of items is not visible on screen - no auto scrolling issues. Also, when top of the list is below the top of my screen - no auto scrolling happen as well.
I have created a Vanilla JavaScript app to test if it is Chrome-specific behaviour - no bug, all good - with Vanilla JS there is no scrolling happen when the list of items re-rendered on the screen. It happens only with React app and is very annoying.
As you can see from my CodeSandbox demo:
- there is no scroll call anywhere but it still happens.
- I don't click anything - just scroll the page to the middle of list and see your page automatically scrolled to the top.
- Height of the list is unchanged. No layout jump should happen here.
Expected behaviour - no scrolling happen when the list is re-rendered.
Any idea how to prevent such auto scrolling?
CodePudding user response:
Looks like react is getting confused with keys. If using random values, everything works as expected:
<div key={Math.random()} className="item">
Update
This behavior is called scroll anchoring. You can disable it like this:
.container {
...
overflow-anchor: none;
}
CodePudding user response:
Hello you can create a component i tried at your codeSandbox and its working
import React, { useEffect, useRef, useState } from "react";
import "./styles.css";
const genList = (size = 10) => {
return Array(size)
.fill(1)
.map((_, i) => i)
.sort(() => (Math.random() > 0.5 ? 1 : -1));
};
/**
* Steps to reproduce the issue:
* 1. Scroll page.
* 2. Wait for re-render of the list.
* 3. See window scrolled to top of list when list re-rendered.
*/
export default function App() {
const ref = useRef();
const [, setRenderTrigger] = useState(0);
useEffect(() => {
const timer = setInterval(() => {
setRenderTrigger((i) => i 1);
}, 1e3);
return () => {
clearInterval(timer);
};
}, []);
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<div className="container">
{/* Adjust list length so it long enough for scroll */}
{genList(10).map((e) => {
return <List> {e}</List>;
})}
</div>
</div>
);
}
const List = ({ children }) => {
return (
<div key={children} className="item">
{children}
</div>
);
};