React挂钩页面滚动位置导致滚动重新渲染



我使用React钩子来跟踪页面上的滚动位置。钩子代码如下:

import { useLayoutEffect, useState } from 'react';
const useScrollPosition = () => {
const [scrollPosition, setScrollPosition] = useState(window.pageYOffset);
useLayoutEffect(() => {
const updatePosition = () => {
setScrollPosition(window.pageYOffset);
};
window.addEventListener('scroll', updatePosition);
return () => window.removeEventListener('scroll', updatePosition);
}, []);
return scrollPosition;
};
export default useScrollPosition;

然后我以各种方式使用它,例如在这个组件中,如果页面滚动超过10px,则将类应用于元素:

const Component = () => {
const scrollPosition = useScrollPosition();
const [scrolled, setScrolled] = useState(false);
useEffect(() => {
const newScrolled = scrollPosition > 10;
if (newScrolled !== scrolled) {
setScrolled(newScrolled);
}
}, [scrollPosition]);
return (
<div
className={clsx(style.element, {
[style.elementScrolled]: scrolled,
})}
>
{children}
</div>
);
};

这一切都工作,并做了我想要实现的,但组件在页面的每次滚动上不断重新呈现。

我的理解是,通过使用钩子来跟踪滚动位置,并通过使用useState/useEffect来只更新变量"scrolled"在滚动位置超过10px阈值的情况下,组件不应该在滚动上连续重新渲染。

我的假设错了吗?这种行为是意料之中的吗?或者我可以改进这一点,以防止不必要的重新渲染?由于

另一个想法是让你的钩子只有在滚动位置超过10pixel时才有反应:


import { useEffect, useState, useRef } from 'react';
const useScrollPosition = () => {
const [ is10, setIs10] = useState(false)
useEffect(() => {
const updatePosition = () => {
if (window.pageYOffset > 10)  {setIs10(true)}
};
window.addEventListener('scroll', updatePosition);
return () => window.removeEventListener('scroll', updatePosition);
}, []);

return is10;
};
export default useScrollPosition;
import React, { useEffect, useState } from "react";
import useScrollPosition from "./useScrollPosition";
const Test = ({children}) => {
const is10 = useScrollPosition();
useEffect(() => {
if (is10) {
console.log('10')
}
}, [is10]);
return (
<div
className=''
>
{children}
</div>
);
};
export default Test

所以你的组件Test只在你达到10px的阈值时呈现,你甚至可以把这个阈值作为参数传递给你的钩子,只是一个想法…

每次有useState,就会重新渲染。在您的情况下,您可以尝试useRef来存储值,而不是useState,因为useRef不会触发新的渲染

如果你想坚持你的早期版本,另一个想法是妥协:让你的组件的子组件被记住,假设你传递了一个名为NestedTest的子组件:

import React from 'react'
const NestedTest = () => {
console.log('hit nested')
return (
<div>nested</div>
)
}
export default React.memo(NestedTest)

您将看到'hit nested'没有显示在控制台中。但这可能不是你一开始所期望的。也许你应该尝试在钩子中使用useRef而不是

最新更新