Sus*_*ain 5 javascript frontend reactjs react-hooks
我试图创建一个元素位置:“固定”,在它滚动到屏幕末尾后,每当它返回到第一个屏幕时,它应该再次获得“相对”位置,但状态正在更改为 true (固定)当它滚动到屏幕末尾但当它向后滚动时,它不会更改为 false (相对)。
const [fixed, setFixed] = useState(() => {
return false;
});
const scrollHandler = () => {
if (window.scrollY > window.innerHeight) {
if (!fixed) {
setFixed(true);
}
} else {
if (fixed) {
setFixed(false);
}
}
};
useEffect(() => {
window.addEventListener("scroll", scrollHandler);
return () => {
window.removeEventListener("scroll", scrollHandler);
};
}, []);
return (
<>
<div
style={{ position: `${fixed ? "fixed" : "relative"}` }}
className={classes.navigationBelt}
></div>
</> );
Run Code Online (Sandbox Code Playgroud)
这是代码解释我将状态命名为“fixed”并将初始值设置为“false”
const [fixed, setFixed] = useState(() => {
return false;
});
Run Code Online (Sandbox Code Playgroud)
当组件安装到 dom 中时,我在窗口上添加了一个用于滚动的事件监听器。
useEffect(() => {
window.addEventListener("scroll", scrollHandler);
return () => {
window.removeEventListener("scroll", scrollHandler);
};
}, []);
Run Code Online (Sandbox Code Playgroud)
为了处理滚动事件,我创建了一个名为“scrollHandler”的函数
const scrollHandler = () => {
if (window.scrollY > window.innerHeight) {
if (!fixed) {
setFixed(true);
}
} else {
if (fixed) {
setFixed(false);
}
}
};
Run Code Online (Sandbox Code Playgroud)
当滚动超过窗口高度并将元素设置为“固定”时,我将“固定”设置为“真”。注意:我仅在“fixed”状态为 false 时更新状态,否则会导致多次重新渲染。
return (
<>
<div
style={{ position: `${fixed ? "fixed" : "relative"}` }}
className={classes.navigationBelt}
></div>
</> );
Run Code Online (Sandbox Code Playgroud)
它工作正常,但是当它向后滚动并且“else”条件命中时,状态(“fixed”)仍然显示为 false,即使它已经更改并且元素已经修复。因为 setFixed(false) 不起作用,因为外部条件仍然为 false。
else {
if (fixed) {
setFixed(false);
}
}
Run Code Online (Sandbox Code Playgroud)
我想知道为什么会发生这种情况?
因为您附加到窗口的变量可以在变量处于(初始状态scrollHandler)时访问。fixedfalse
您将其附加到useEffect仅运行一次的文件中,因此它将始终保留scrollHandler.
您可以将fixed作为依赖项传递给useEffect,这样它将刷新/更新事件处理程序。
useEffect(() => {
window.addEventListener("scroll", scrollHandler);
return () => {
window.removeEventListener("scroll", scrollHandler);
};
}, [fixed]);
Run Code Online (Sandbox Code Playgroud)
上面的解决方案有一个“问题”,您需要知道做什么scrollHandler才能指定/更新useEffect.
useEffect更明智的方法是在更改时重新运行,因为它是在(这是真正的依赖项)scrollHandler内部使用的useEffectuseEffect
useEffect(() => {
window.addEventListener("scroll", scrollHandler);
return () => {
window.removeEventListener("scroll", scrollHandler);
};
}, [fixed]);
Run Code Online (Sandbox Code Playgroud)
但是,由于您的代码将scrollHandler在组件的每次重新渲染中更改处理程序,因此您应该尝试使其尽可能“稳定”,即为该函数保留/重新使用相同的引用,而其自己的依赖项是相同的。为此,您可以使用useCallback并将其fixed用作其依赖项。
useEffect(() => {
window.addEventListener("scroll", scrollHandler);
return () => {
window.removeEventListener("scroll", scrollHandler);
};
}, [scrollHandler]);
Run Code Online (Sandbox Code Playgroud)