这是一个关于如何在 React 中最好地产生视差效果的一般性问题!
我想根据滚动位置直接更新元素的位置。目标是让元素看起来固定。我尝试了一些不同的方法,但在 Mac 上的 Safari(有时是 Chrome)和某些设备上总是遇到断断续续/闪烁行为的问题。
我尝试过修复主体并让根 div 滚动(以消除某些浏览器的弹性效果),但存在同样的问题。我还尝试将translateZ(0) 添加到事件3d 渲染中,但也出现同样的问题。
这是由 React 更新组件频率的某些机制引起的还是浏览器问题?
有没有更好的方法来创建这种效果?
import React, { useState, useEffect } from "react";
const useScroll = () => {
const [scroll, setScroll] = useState(0);
useEffect(() => {
window.addEventListener("scroll", scrollHandler);
return () => {
window.removeEventListener("scroll", scrollHandler);
};
}, []);
const scrollHandler = () => {
setScroll(window.scrollY);
};
return scroll;
};
export default function App() {
const scrollPos = useScroll();
return (
<main style={{ height: "300vh" }}>
<div>Normal Div</div>
<div style={{ transform: `translateY(${scrollPos}px)` }}>Fixed Div</div>
</main>
);
}
这是问题的简单再现。它给我带来了同样的问题(在某些浏览器中不稳定,尤其是 Mac 上的 Safari)。
最佳答案
将滚动位置保持在组件状态确实需要在每次触发滚动事件时重新渲染所述组件。射速巨大,这就是为什么DOM mutations should be avoided .
在你的例子中,React 不仅需要更新状态和 reconcile ,它还必须改变 DOM 以替换最后一个 div
,因为它的 props 之一 style
在每次渲染时都不同。随着组件变大,波动效应会变得更糟。
=> 尽管 React 具有高性能,但滚动事件是一种特殊的野兽,因此有资格使用命令式句柄:
const useScrollHandler = (handler) => {
useEffect(() => {
window.addEventListener('scroll', handler)
return () => {
window.removeEventListener('scroll', handler)
}
}, [])
}
const FixedDiv = (props) => {
const ref = useRef()
const handler = () => { ref.current.style.transform = `translateY(${window.scrollY}px)` }
useScrollHandler(handler)
return <div ref={ref} {...props} />
}
function App() {
return (
<main style={{ height: '300vh' }}>
<div>Normal Div</div>
<FixedDiv>Fixed Div</FixedDiv>
</main>
)
}
关于reactjs - React 中不稳定的视差。最佳实践是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57341698/