【发布时间】:2020-03-17 18:45:46
【问题描述】:
我正在编写一个React Header 组件,该组件将在滚动时滑出。 (代码在底部)
我在
useEffect钩子中分配了一个事件处理程序,当滚动事件发生时它会调用handleChange函数。我已经将此handleChange函数包装在useCallback钩子中以提高性能(无需在每次渲染时重新实例化)。我还用
React.memo包装了整个函数。-
我将滚动位置存储在
李>useRef中,因为更改不需要触发重新渲染,重新渲染将由setVisibility内部handleChange引起。
现在,这个组件的渲染次数超出了我的预期。我在组件中的每个“操作”中添加了一个 console.log 来跟踪正在发生的事情。我已经复制了 Chrome DevTools 控制台输出。 安装后,控制台显示:
Render 0
Render 0
Added event listener
为什么在运行 useEffect 之前它会渲染两次?
当我在页面上滚动时,控制台显示:
Handling scroll
Previous scroll: 249.5625
Scroll: 251.5625
Render 249.5625
Render 249.5625
Handling scroll
Previous scroll: 251.5625
Scroll: 252.5625
Render 251.5625
Render 251.5625
Handling scroll
Previous scroll: 252.5625
Scroll: 254.5625
所以我的handleChange函数被调用了,但是每次滚动位置改变时它都会重新渲染组件两次?
请帮我弄清楚为什么当状态改变时这个组件会渲染两次。 编辑:我发现它在滑出或滑入时甚至可以渲染 4 次。
//I'm using styled-components and the prop simply tranforms the header up when the visible prop is true
function Header(): JSX.Element {
const [visible, setVisibility] = useState(true);
const scrollPosition = useRef(0);
const handleScroll = useCallback(() => {
//Non-absolute values will result in comparison errors
const currentScrollPosition = Math.abs(
document.body.getBoundingClientRect().top
);
//Testing
console.log("Handling scroll");
console.log("Previous scroll:", scrollPosition.current);
console.log("Scroll:", currentScrollPosition);
//Do not hide when scrolling down for the first time until user scroll down a little
if (currentScrollPosition <= 150) {
setVisibility(true);
} else setVisibility(scrollPosition.current > currentScrollPosition);
//Update ref value to new scrolling position
scrollPosition.current = currentScrollPosition;
}, []);
useEffect(() => {
window.addEventListener("scroll", handleScroll);
//Testing
console.log("Added event listener");
return (): void => {
window.removeEventListener("scroll", handleScroll);
//Testing
console.log("Removed event listener");
};
}, []);
//Testing
console.log("Render", scrollPosition.current);
return (
<>
<S_header visible={!visible}>
<h3>Work on preventing excessive rendering </h3>
</S_header>
</>
);
}
export default memo(Header);
【问题讨论】:
-
为什么在将您的代码粘贴到代码沙箱时无法复制您的问题? codesandbox.io/s/… ,它只渲染一次
-
我正在使用 Next.js,但这不应该有任何影响,因为该组件没有任何道具
标签: reactjs