如何防止React在重新渲染时自动滚动页面?

5
我遇到了一个奇怪而烦人的React问题 - React在重新渲染时会自动滚动页面。
CodeSandbox上的演示应用程序 - https://codesandbox.io/s/react-scroll-bug-demo-y7u50j?file=/src/App.js 复现步骤:
  • 将页面滚动到列表中间,使其第一个元素不再可见。
  • 等待重新渲染发生。
  • 查看您的页面是否自动滚动,以便第一个元素再次可见。
问题 - 当满足以下条件时,React会自动滚动页面:
  1. 我有一个垂直项目列表。
  2. 列表重新渲染(项目更改其顺序)。
  3. 列表在屏幕上可见,但第一个元素不可见(在屏幕上方)。
因此,当项目列表在屏幕上不可见时 - 没有自动滚动问题。 同样,当列表顶部在我的屏幕顶部以下时 - 也不会发生自动滚动。
我创建了一个Vanilla JavaScript应用程序来测试它是否是仅限于Chrome的行为 - 没有错误,一切正常 - 使用Vanilla JS时,在屏幕上重新呈现项目列表时不会发生滚动。这种情况仅适用于React应用程序,非常令人烦恼。
如您从我的CodeSandbox演示中所见:
  • 没有任何滚动调用,但它仍然发生。
  • 我没有点击任何东西 - 只需将页面滚动到列表中间,您的页面就会自动滚动到顶部。
  • 列表的高度没有改变。这里不应该发生布局跳跃。
预期行为 - 当重新呈现列表时不会发生滚动。
有什么想法可以防止这种自动滚动?
2个回答

9

看起来React对键值(keys)感到困惑。如果使用随机值,一切都按预期工作:

<div key={Math.random()} className="item">

更新

这种行为被称为滚动锚定。您可以通过以下方法禁用它:

.container {
  ...
  overflow-anchor: none;
}

0

你好,你可以创建一个组件。我在你的 CodeSandbox 上尝试了一下,它可以工作。

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>
  );
};

1
这是因为您在映射过程中没有定义关键属性。您应该在控制台中看到一个警告,指出缺少关键属性。在另一个组件内定义关键属性是错误的位置,并且对于渲染优化没有任何好处。 - Oleksii Shnyra

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接