我正在尝试实现一个简单的Header组件,该标题在到达某个滚动位置后将隐藏。
我想出了以下解决方案,并认为仅当Header
的值实际发生变化(这不是正在发生的情况)时,才会重新呈现headerState
组件。即使滚动setHeaderState
甚至没有被调用,该组件也会在滚动位置的每次更改时重新呈现。
我在这里想念什么?是否正在重新渲染,因为我正在使用useWindowScroll
,可以以某种方式避免它吗?
import { useWindowScroll } from "react-use";
const useHeaderState = () => {
const [ headerState, setHeaderState ] = React.useState(0);
const { y } = useWindowScroll();
React.useEffect(() => {
if (y > 50 && headerState !== 1) {
setHeaderState(1);
}
}, [y, headerState]);
return headerState;
}
const Header: React.FC = () => {
const headerState = useHeaderState();
console.log("rerender");
return (
<header
className={cn(
"fixed top-0 left-0 w-full text-white z-30 transition-transform transition-250",
headerState === 1 && "-translate-16",
)}
>
<div className="bg-gray-900 h-16 md:h-32">header</div>
</header>
)
};
答案 0 :(得分:1)
重新渲染确实是由于useWindowScroll
引起的。
如source所示,每次窗口滚动时,useWindowScroll
都会调用setState。
为避免渲染浪费,您可以自己监听窗口滚动,而无需使用useWindowScroll
,例如:
const useHeaderState = () => {
const [headerState, setHeaderState] = React.useState(0);
const frame = useRef(0);
useEffect(() => {
const handler = () => {
cancelAnimationFrame(frame.current);
frame.current = requestAnimationFrame(() => {
if (window.pageYOffset > 50 && headerState !== 1) {
setHeaderState(1);
}
});
};
window.addEventListener("scroll", handler, {
capture: false,
passive: true
});
return () => {
cancelAnimationFrame(frame.current);
window.removeEventListener("scroll", handler);
};
});
return headerState;
};
答案 1 :(得分:0)
您说的问题是,内部%hhu
可能会自行调用unsigned char *
钩子来调用useWindowScroll
。
通常,组件重新渲染应该不是问题吗?这有问题吗?
但是,一种选择是将setState
钩移到父级,然后使用React.memo
来记住useState
,并且仅在道具发生更改时才重新渲染。
useHeaderState