You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React重渲染时如何避免未变更组件的滚动条被重置到顶部

解决方案

方案1:阻止SecondComponent不必要重渲染(最优解)

导致问题的核心原因是父组件状态更新时,所有子组件默认都会跟随重渲染,哪怕子组件的props没有实际变化。你可以通过React.memo + React.useCallback的组合跳过SecondComponent的重渲染:

  1. 用React.memo包裹SecondComponent,开启props浅比较,只有props变化时才触发重渲染:
const SecondComponent = React.memo((props) => {
  // 原有SecondComponent的业务逻辑保持不变
})
  1. 父组件中用React.useCallback缓存onChange回调,避免每次父组件渲染都生成新的函数引用(React保证state的setter函数引用永远稳定,所以依赖项可以留空):
const A = () => {
    const [value1, setValue1] = React.useState(true);
    const [value2, setValue2] = React.useState(true);
    // 缓存onChange回调
    const handleChange = React.useCallback(() => {
        setValue1(false);
        setValue2(false);
    }, [])

    return (
    <div>
        <div className="first-comp">
             <FirstComponent data1={value1} data2={value2} />
        </div>
        <div className="second-comp">
             <SecondComponent onChange={handleChange} />
        </div>
    </div>
    )
}

调整后SecondComponent的props不会发生变化,会直接跳过重渲染,滚动位置自然不会被重置。

方案2:手动保存/恢复滚动位置

如果业务逻辑不允许阻止SecondComponent重渲染,可以在重渲染前后手动保存、恢复滚动位置:

  1. 用React.forwardRef给SecondComponent的内部滚动容器挂载ref:
const SecondComponent = React.forwardRef((props, ref) => {
  // 把ref绑定到内部产生滚动的DOM节点上
  return <div ref={ref} className="second-comp-scroll-area">
    {/* 原有组件内容 */}
  </div>
})
  1. 父组件中存储滚动位置,组件更新后恢复:
const A = () => {
    const [value1, setValue1] = React.useState(true);
    const [value2, setValue2] = React.useState(true);
    const secondCompRef = React.useRef(null);
    const savedScrollTop = React.useRef(0);

    const handleChange = () => {
        // 触发状态更新前先保存当前滚动位置
        if(secondCompRef.current) {
            savedScrollTop.current = secondCompRef.current.scrollTop
        }
        setValue1(false);
        setValue2(false);
    }

    // 状态更新完成后恢复滚动位置
    React.useEffect(() => {
        if(secondCompRef.current && savedScrollTop.current) {
            secondCompRef.current.scrollTop = savedScrollTop.current
        }
    }, [value1, value2])

    return (
    <div>
        <div className="first-comp">
             <FirstComponent data1={value1} data2={value2} />
        </div>
        <div className="second-comp">
             <SecondComponent ref={secondCompRef} onChange={handleChange} />
        </div>
    </div>
    )
}

额外排查点

如果调整后SecondComponent仍然出现不必要重渲染,可以检查两个点:

  • 传给SecondComponent的其他props是不是每次渲染都会生成新的引用(比如对象、数组没有用useMemo缓存)
  • SecondComponent内部如果有列表渲染,是不是用了索引作为key,key不稳定也会导致DOM重新生成、滚动条复位。

内容的提问来源于stack exchange,提问作者Harsh Agarwal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 16:36:01